| Directory: | ./ |
|---|---|
| File: | sql/sql_optimizer.cc |
| Date: | 2022-12-06 21:40:42 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 4219 | 4409 | 95.7% |
| Branches: | 5370 | 7293 | 73.6% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* Copyright (c) 2000, 2022, Oracle and/or its affiliates. | ||
| 2 | |||
| 3 | This program is free software; you can redistribute it and/or modify | ||
| 4 | it under the terms of the GNU General Public License, version 2.0, | ||
| 5 | as published by the Free Software Foundation. | ||
| 6 | |||
| 7 | This program is also distributed with certain software (including | ||
| 8 | but not limited to OpenSSL) that is licensed under separate terms, | ||
| 9 | as designated in a particular file or component or in included license | ||
| 10 | documentation. The authors of MySQL hereby grant you an additional | ||
| 11 | permission to link the program and your derivative works with the | ||
| 12 | separately licensed software that they have included with MySQL. | ||
| 13 | |||
| 14 | This program is distributed in the hope that it will be useful, | ||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | GNU General Public License, version 2.0, for more details. | ||
| 18 | |||
| 19 | You should have received a copy of the GNU General Public License | ||
| 20 | along with this program; if not, write to the Free Software | ||
| 21 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
| 22 | |||
| 23 | /** | ||
| 24 | @file | ||
| 25 | |||
| 26 | @brief Optimize query expressions: Make optimal table join order, select | ||
| 27 | optimal access methods per table, apply grouping, sorting and | ||
| 28 | limit processing. | ||
| 29 | |||
| 30 | @defgroup Query_Optimizer Query Optimizer | ||
| 31 | @{ | ||
| 32 | */ | ||
| 33 | |||
| 34 | #include "sql/sql_optimizer.h" | ||
| 35 | #include "sql/sql_optimizer_internal.h" | ||
| 36 | |||
| 37 | #include <limits.h> | ||
| 38 | #include <algorithm> | ||
| 39 | #include <atomic> | ||
| 40 | #include <deque> | ||
| 41 | #include <new> | ||
| 42 | #include <string> | ||
| 43 | #include <utility> | ||
| 44 | #include <vector> | ||
| 45 | |||
| 46 | #include "field_types.h" // enum_field_types | ||
| 47 | #include "ft_global.h" | ||
| 48 | #include "m_ctype.h" | ||
| 49 | #include "mem_root_deque.h" | ||
| 50 | #include "memory_debugging.h" | ||
| 51 | #include "my_bit.h" // my_count_bits | ||
| 52 | #include "my_bitmap.h" | ||
| 53 | #include "my_compiler.h" | ||
| 54 | #include "my_dbug.h" | ||
| 55 | #include "my_inttypes.h" | ||
| 56 | #include "my_sqlcommand.h" | ||
| 57 | #include "my_sys.h" | ||
| 58 | #include "mysql/udf_registration_types.h" | ||
| 59 | #include "mysql_com.h" | ||
| 60 | #include "mysqld_error.h" | ||
| 61 | #include "sql/check_stack.h" | ||
| 62 | #include "sql/current_thd.h" | ||
| 63 | #include "sql/debug_sync.h" // DEBUG_SYNC | ||
| 64 | #include "sql/derror.h" // ER_THD | ||
| 65 | #include "sql/enum_query_type.h" | ||
| 66 | #include "sql/error_handler.h" // Functional_index_error_handler | ||
| 67 | #include "sql/handler.h" | ||
| 68 | #include "sql/item.h" | ||
| 69 | #include "sql/item_cmpfunc.h" | ||
| 70 | #include "sql/item_func.h" | ||
| 71 | #include "sql/item_row.h" | ||
| 72 | #include "sql/item_subselect.h" | ||
| 73 | #include "sql/item_sum.h" // Item_sum | ||
| 74 | #include "sql/iterators/basic_row_iterators.h" | ||
| 75 | #include "sql/iterators/timing_iterator.h" | ||
| 76 | #include "sql/join_optimizer/access_path.h" | ||
| 77 | #include "sql/join_optimizer/join_optimizer.h" | ||
| 78 | #include "sql/key.h" | ||
| 79 | #include "sql/key_spec.h" | ||
| 80 | #include "sql/lock.h" // mysql_unlock_some_tables | ||
| 81 | #include "sql/mysqld.h" // stage_optimizing | ||
| 82 | #include "sql/nested_join.h" | ||
| 83 | #include "sql/opt_costmodel.h" | ||
| 84 | #include "sql/opt_explain.h" // join_type_str | ||
| 85 | #include "sql/opt_hints.h" // hint_table_state | ||
| 86 | #include "sql/opt_trace.h" // Opt_trace_object | ||
| 87 | #include "sql/opt_trace_context.h" | ||
| 88 | #include "sql/parse_tree_node_base.h" | ||
| 89 | #include "sql/parser_yystype.h" | ||
| 90 | #include "sql/query_options.h" | ||
| 91 | #include "sql/query_result.h" | ||
| 92 | #include "sql/range_optimizer/partition_pruning.h" | ||
| 93 | #include "sql/range_optimizer/path_helpers.h" | ||
| 94 | #include "sql/range_optimizer/range_optimizer.h" | ||
| 95 | #include "sql/sql_base.h" // init_ftfuncs | ||
| 96 | #include "sql/sql_bitmap.h" | ||
| 97 | #include "sql/sql_class.h" | ||
| 98 | #include "sql/sql_const.h" | ||
| 99 | #include "sql/sql_const_folding.h" | ||
| 100 | #include "sql/sql_error.h" | ||
| 101 | #include "sql/sql_join_buffer.h" // JOIN_CACHE | ||
| 102 | #include "sql/sql_planner.h" // calculate_condition_filter | ||
| 103 | #include "sql/sql_test.h" // print_where | ||
| 104 | #include "sql/sql_tmp_table.h" | ||
| 105 | #include "sql/system_variables.h" | ||
| 106 | #include "sql/table.h" | ||
| 107 | #include "sql/thd_raii.h" | ||
| 108 | #include "sql/window.h" | ||
| 109 | #include "sql_string.h" | ||
| 110 | #include "template_utils.h" | ||
| 111 | |||
| 112 | using std::max; | ||
| 113 | using std::min; | ||
| 114 | |||
| 115 | const char *antijoin_null_cond = "<ANTIJOIN-NULL>"; | ||
| 116 | |||
| 117 | static bool optimize_semijoin_nests_for_materialization(JOIN *join); | ||
| 118 | static void calculate_materialization_costs(JOIN *join, TABLE_LIST *sj_nest, | ||
| 119 | uint n_tables, | ||
| 120 | Semijoin_mat_optimize *sjm); | ||
| 121 | static bool make_join_query_block(JOIN *join, Item *item); | ||
| 122 | static bool list_contains_unique_index(JOIN_TAB *tab, | ||
| 123 | bool (*find_func)(Field *, void *), | ||
| 124 | void *data); | ||
| 125 | static bool find_field_in_item_list(Field *field, void *data); | ||
| 126 | static bool find_field_in_order_list(Field *field, void *data); | ||
| 127 | static TABLE *get_sort_by_table(ORDER *a, ORDER *b, TABLE_LIST *tables); | ||
| 128 | static void trace_table_dependencies(Opt_trace_context *trace, | ||
| 129 | JOIN_TAB *join_tabs, uint table_count); | ||
| 130 | static bool update_ref_and_keys(THD *thd, Key_use_array *keyuse, | ||
| 131 | JOIN_TAB *join_tab, uint tables, Item *cond, | ||
| 132 | table_map normal_tables, | ||
| 133 | Query_block *query_block, | ||
| 134 | SARGABLE_PARAM **sargables); | ||
| 135 | static bool pull_out_semijoin_tables(JOIN *join); | ||
| 136 | static void add_loose_index_scan_and_skip_scan_keys(JOIN *join, | ||
| 137 | JOIN_TAB *join_tab); | ||
| 138 | static ha_rows get_quick_record_count(THD *thd, JOIN_TAB *tab, ha_rows limit); | ||
| 139 | static bool only_eq_ref_tables(JOIN *join, ORDER *order, table_map tables, | ||
| 140 | table_map *cached_eq_ref_tables, | ||
| 141 | table_map *eq_ref_tables); | ||
| 142 | static bool setup_join_buffering(JOIN_TAB *tab, JOIN *join, uint no_jbuf_after); | ||
| 143 | |||
| 144 | static bool test_if_skip_sort_order(JOIN_TAB *tab, ORDER_with_src &order, | ||
| 145 | ha_rows select_limit, const bool no_changes, | ||
| 146 | const Key_map *map, int *best_idx); | ||
| 147 | |||
| 148 | static Item_func_match *test_if_ft_index_order(ORDER *order); | ||
| 149 | |||
| 150 | static uint32 get_key_length_tmp_table(Item *item); | ||
| 151 | static bool can_switch_from_ref_to_range(THD *thd, JOIN_TAB *tab, | ||
| 152 | enum_order ordering, | ||
| 153 | bool recheck_range); | ||
| 154 | |||
| 155 | static bool has_not_null_predicate(Item *cond, Item_field *not_null_item); | ||
| 156 | |||
| 157 | 9987004 | JOIN::JOIN(THD *thd_arg, Query_block *select) | |
| 158 | 9987004 | : query_block(select), | |
| 159 | 9987004 | thd(thd_arg), | |
| 160 | // @todo Can this be substituted with select->is_explicitly_grouped()? | ||
| 161 | 19974036 | grouped(select->is_explicitly_grouped()), | |
| 162 | // Inner tables may always be considered to be constant: | ||
| 163 | 9987013 | const_table_map(INNER_TABLE_BIT), | |
| 164 | 9987013 | found_const_table_map(INNER_TABLE_BIT), | |
| 165 | // Needed in case optimizer short-cuts, set properly in | ||
| 166 | // make_tmp_tables_info() | ||
| 167 | 9987013 | fields(&select->fields), | |
| 168 | 9987029 | tmp_table_param(thd_arg->mem_root), | |
| 169 | 9987011 | lock(thd->lock), | |
| 170 | // @todo Can this be substituted with select->is_implicitly_grouped()? | ||
| 171 | 9987011 | implicit_grouping(select->is_implicitly_grouped()), | |
| 172 | 9987018 | select_distinct(select->is_distinct()), | |
| 173 | 9987026 | keyuse_array(thd->mem_root), | |
| 174 | 9987010 | order(select->order_list.first, ESC_ORDER_BY), | |
| 175 | 9987011 | group_list(select->group_list.first, ESC_GROUP_BY), | |
| 176 | 9987012 | m_windows(select->m_windows), | |
| 177 | /* | ||
| 178 | Those four members are meaningless before JOIN::optimize(), so force a | ||
| 179 | crash if they are used before that. | ||
| 180 | */ | ||
| 181 | 9987010 | where_cond(reinterpret_cast<Item *>(1)), | |
| 182 | 9987010 | having_cond(reinterpret_cast<Item *>(1)), | |
| 183 | 9987010 | having_for_explain(reinterpret_cast<Item *>(1)), | |
| 184 | 9987010 | tables_list(reinterpret_cast<TABLE_LIST *>(1)), | |
| 185 | 9987010 | current_ref_item_slice(REF_SLICE_SAVED_BASE), | |
| 186 |
2/4✓ Branch 0 taken 9987011 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9987010 times.
✗ Branch 3 not taken.
|
39948069 | with_json_agg(select->json_agg_func_used()) { |
| 187 | 9987018 | rollup_state = RollupState::NONE; | |
| 188 |
2/2✓ Branch 0 taken 641075 times.
✓ Branch 1 taken 9345943 times.
|
9987018 | if (select->order_list.first) explain_flags.set(ESC_ORDER_BY, ESP_EXISTS); |
| 189 |
2/2✓ Branch 0 taken 10533 times.
✓ Branch 1 taken 9976484 times.
|
9987017 | if (select->group_list.first) explain_flags.set(ESC_GROUP_BY, ESP_EXISTS); |
| 190 |
2/2✓ Branch 0 taken 4046 times.
✓ Branch 1 taken 9982980 times.
|
9987017 | if (select->is_distinct()) explain_flags.set(ESC_DISTINCT, ESP_EXISTS); |
| 191 |
2/2✓ Branch 0 taken 1523 times.
✓ Branch 1 taken 9985503 times.
|
9987026 | if (m_windows.elements > 0) explain_flags.set(ESC_WINDOWING, ESP_EXISTS); |
| 192 | // Calculate the number of groups | ||
| 193 |
2/2✓ Branch 0 taken 18341 times.
✓ Branch 1 taken 9987023 times.
|
10005364 | for (ORDER *group = group_list.order; group; group = group->next) |
| 194 | 18341 | send_group_parts++; | |
| 195 | 9987023 | } | |
| 196 | |||
| 197 | 580744 | bool JOIN::alloc_ref_item_slice(THD *thd_arg, int sliceno) { | |
| 198 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 580744 times.
|
580744 | assert(sliceno > 0); |
| 199 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 580744 times.
|
580744 | assert(ref_items[sliceno].is_null()); |
| 200 | 580744 | size_t count = ref_items[0].size(); | |
| 201 | 580743 | Item **slice = thd_arg->mem_root->ArrayAlloc<Item *>(count); | |
| 202 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 580744 times.
|
580744 | if (slice == nullptr) return true; |
| 203 | 580744 | ref_items[sliceno] = Ref_item_array(slice, count); | |
| 204 | 580744 | return false; | |
| 205 | } | ||
| 206 | |||
| 207 | 9923718 | bool JOIN::alloc_indirection_slices() { | |
| 208 | 9923718 | const int num_slices = REF_SLICE_WIN_1 + m_windows.elements; | |
| 209 | |||
| 210 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9923718 times.
|
9923718 | assert(ref_items == nullptr); |
| 211 | 9923718 | ref_items = (*THR_MALLOC)->ArrayAlloc<Ref_item_array>(num_slices); | |
| 212 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9923737 times.
|
9923737 | if (ref_items == nullptr) return true; |
| 213 | |||
| 214 | 9923738 | tmp_fields = | |
| 215 | 9923737 | (*THR_MALLOC) | |
| 216 | 9923742 | ->ArrayAlloc<mem_root_deque<Item *>>(num_slices, *THR_MALLOC); | |
| 217 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9923738 times.
|
9923738 | if (tmp_fields == nullptr) return true; |
| 218 | |||
| 219 | 9923738 | return false; | |
| 220 | } | ||
| 221 | |||
| 222 | /** | ||
| 223 | The List<Item_equal> in COND_EQUAL partially overlaps with the argument list | ||
| 224 | in various Item_cond via C-style casts. However, the hypergraph optimizer can | ||
| 225 | modify the lists in Item_cond (by calling compile()), causing an Item_equal to | ||
| 226 | be replaced with Item_func_eq, and this can cause a List<Item_equal> not to | ||
| 227 | contain Item_equal pointers anymore. This is is obviously bad if anybody wants | ||
| 228 | to actually look into these lists after optimization (in particular, NDB | ||
| 229 | wants this). | ||
| 230 | |||
| 231 | Since untangling this spaghetti seems very hard, we solve it by brute force: | ||
| 232 | Make a copy of all the COND_EQUAL lists, so that they no longer reach into the | ||
| 233 | Item_cond. This allows us to modify the Item_cond at will. | ||
| 234 | */ | ||
| 235 | 53 | static void SaveCondEqualLists(COND_EQUAL *cond_equal) { | |
| 236 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 7 times.
|
53 | if (cond_equal == nullptr) { |
| 237 | 46 | return; | |
| 238 | } | ||
| 239 | 7 | List<Item_equal> copy; | |
| 240 |
5/8✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 7 times.
|
12 | for (Item_equal &item : cond_equal->current_level) { |
| 241 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | copy.push_back(&item); |
| 242 | } | ||
| 243 | 7 | cond_equal->current_level = std::move(copy); | |
| 244 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | SaveCondEqualLists(cond_equal->upper_levels); |
| 245 | } | ||
| 246 | |||
| 247 | /** | ||
| 248 | Optimizes one query block into a query execution plan (QEP.) | ||
| 249 | |||
| 250 | This is the entry point to the query optimization phase. This phase | ||
| 251 | applies both logical (equivalent) query rewrites, cost-based join | ||
| 252 | optimization, and rule-based access path selection. Once an optimal | ||
| 253 | plan is found, the member function creates/initializes all | ||
| 254 | structures needed for query execution. The main optimization phases | ||
| 255 | are outlined below: | ||
| 256 | |||
| 257 | -# Logical transformations: | ||
| 258 | - Outer to inner joins transformation. | ||
| 259 | - Equality/constant propagation. | ||
| 260 | - Partition pruning. | ||
| 261 | - COUNT(*), MIN(), MAX() constant substitution in case of | ||
| 262 | implicit grouping. | ||
| 263 | - ORDER BY optimization. | ||
| 264 | -# Perform cost-based optimization of table order and access path | ||
| 265 | selection. See JOIN::make_join_plan() | ||
| 266 | -# Post-join order optimization: | ||
| 267 | - Create optimal table conditions from the where clause and the | ||
| 268 | join conditions. | ||
| 269 | - Inject outer-join guarding conditions. | ||
| 270 | - Adjust data access methods after determining table condition | ||
| 271 | (several times.) | ||
| 272 | - Optimize ORDER BY/DISTINCT. | ||
| 273 | -# Code generation | ||
| 274 | - Set data access functions. | ||
| 275 | - Try to optimize away sorting/distinct. | ||
| 276 | - Setup temporary table usage for grouping and/or sorting. | ||
| 277 | |||
| 278 | @retval false Success. | ||
| 279 | @retval true Error, error code saved in member JOIN::error. | ||
| 280 | */ | ||
| 281 | 9923734 | bool JOIN::optimize(bool finalize_access_paths) { | |
| 282 |
1/2✓ Branch 0 taken 9923749 times.
✗ Branch 1 not taken.
|
9923734 | DBUG_TRACE; |
| 283 | |||
| 284 | 9923749 | uint no_jbuf_after = UINT_MAX; | |
| 285 | |||
| 286 |
5/6✓ Branch 0 taken 1930025 times.
✓ Branch 1 taken 7993724 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1930024 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
9923749 | assert(query_block->leaf_table_count == 0 || |
| 287 | thd->lex->is_query_tables_locked() || | ||
| 288 | query_block == query_expression()->fake_query_block); | ||
| 289 |
4/6✓ Branch 0 taken 9923741 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 9923742 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9923744 times.
✗ Branch 5 not taken.
|
9923749 | assert(tables == 0 && primary_tables == 0 && tables_list == (TABLE_LIST *)1); |
| 290 | |||
| 291 | // to prevent double initialization on EXPLAIN | ||
| 292 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9923744 times.
|
9923744 | if (optimized) return false; |
| 293 | |||
| 294 |
3/4✓ Branch 0 taken 9900279 times.
✓ Branch 1 taken 23462 times.
✓ Branch 2 taken 9900287 times.
✗ Branch 3 not taken.
|
9923744 | DEBUG_SYNC(thd, "before_join_optimize"); |
| 295 | |||
| 296 |
1/2✓ Branch 0 taken 9923743 times.
✗ Branch 1 not taken.
|
9923749 | THD_STAGE_INFO(thd, stage_optimizing); |
| 297 | |||
| 298 | 9923743 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 299 |
1/2✓ Branch 0 taken 9923747 times.
✗ Branch 1 not taken.
|
9923743 | Opt_trace_object trace_wrapper(trace); |
| 300 |
1/2✓ Branch 0 taken 9923748 times.
✗ Branch 1 not taken.
|
9923747 | Opt_trace_object trace_optimize(trace, "join_optimization"); |
| 301 |
1/2✓ Branch 0 taken 9923748 times.
✗ Branch 1 not taken.
|
9923748 | trace_optimize.add_select_number(query_block->select_number); |
| 302 |
1/2✓ Branch 0 taken 9923740 times.
✗ Branch 1 not taken.
|
9923748 | Opt_trace_array trace_steps(trace, "steps"); |
| 303 | |||
| 304 |
1/2✓ Branch 0 taken 9923749 times.
✗ Branch 1 not taken.
|
9923740 | count_field_types(query_block, &tmp_table_param, *fields, false, false); |
| 305 | |||
| 306 |
5/6✓ Branch 0 taken 440034 times.
✓ Branch 1 taken 9483715 times.
✓ Branch 2 taken 431563 times.
✓ Branch 3 taken 8471 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 431563 times.
|
9923749 | assert(tmp_table_param.sum_func_count == 0 || !group_list.empty() || |
| 307 | implicit_grouping); | ||
| 308 | |||
| 309 | 9923749 | const bool has_windows = m_windows.elements != 0; | |
| 310 | |||
| 311 |
7/8✓ Branch 0 taken 1523 times.
✓ Branch 1 taken 9922226 times.
✓ Branch 2 taken 1523 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1518 times.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 9923744 times.
|
9923749 | if (has_windows && Window::setup_windows2(thd, &m_windows)) |
| 312 | 5 | return true; /* purecov: inspected */ | |
| 313 | |||
| 314 |
5/8✓ Branch 0 taken 334 times.
✓ Branch 1 taken 9923410 times.
✓ Branch 2 taken 334 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 334 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9923744 times.
|
9923744 | if (query_block->olap == ROLLUP_TYPE && optimize_rollup()) |
| 315 | ✗ | return true; /* purecov: inspected */ | |
| 316 | |||
| 317 |
2/4✓ Branch 0 taken 9923730 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9923730 times.
|
9923744 | if (alloc_func_list()) return true; /* purecov: inspected */ |
| 318 | |||
| 319 |
2/4✓ Branch 0 taken 9923740 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9923740 times.
|
9923730 | if (query_block->get_optimizable_conditions(thd, &where_cond, &having_cond)) |
| 320 | ✗ | return true; | |
| 321 | |||
| 322 |
4/6✓ Branch 0 taken 9923723 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9923735 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 920 times.
✓ Branch 5 taken 9923735 times.
|
9924660 | for (Item_rollup_group_item *item : query_block->rollup_group_items) { |
| 323 |
1/2✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
|
920 | rollup_group_items.push_back(item); |
| 324 | } | ||
| 325 |
4/6✓ Branch 0 taken 9923738 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9923739 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 315 times.
✓ Branch 5 taken 9923739 times.
|
9924050 | for (Item_rollup_sum_switcher *item : query_block->rollup_sums) { |
| 326 |
1/2✓ Branch 0 taken 315 times.
✗ Branch 1 not taken.
|
315 | rollup_sums.push_back(item); |
| 327 | } | ||
| 328 | |||
| 329 | 9923739 | set_optimized(); | |
| 330 | |||
| 331 | 9923723 | tables_list = query_block->leaf_tables; | |
| 332 | |||
| 333 |
2/4✓ Branch 0 taken 9923739 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9923739 times.
|
9923723 | if (alloc_indirection_slices()) return true; |
| 334 | |||
| 335 | // The base ref items from query block are assigned as JOIN's ref items | ||
| 336 | 9923739 | ref_items[REF_SLICE_ACTIVE] = query_block->base_ref_items; | |
| 337 | |||
| 338 | /* dump_TABLE_LIST_graph(query_block, query_block->leaf_tables); */ | ||
| 339 | /* | ||
| 340 | Run optimize phase for all derived tables/views used in this SELECT, | ||
| 341 | including those in semi-joins. | ||
| 342 | */ | ||
| 343 | // if (query_block->materialized_derived_table_count) { | ||
| 344 | { // WL#6570 | ||
| 345 |
2/2✓ Branch 0 taken 3947930 times.
✓ Branch 1 taken 9923734 times.
|
13871664 | for (TABLE_LIST *tl = query_block->leaf_tables; tl; tl = tl->next_leaf) { |
| 346 | 3947930 | tl->access_path_for_derived = nullptr; | |
| 347 |
2/2✓ Branch 0 taken 145791 times.
✓ Branch 1 taken 3802141 times.
|
3947930 | if (tl->is_view_or_derived()) { |
| 348 |
3/4✓ Branch 0 taken 145792 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 145776 times.
|
145791 | if (tl->optimize_derived(thd)) return true; |
| 349 |
2/2✓ Branch 0 taken 601 times.
✓ Branch 1 taken 3801546 times.
|
3802141 | } else if (tl->is_table_function()) { |
| 350 | 601 | TABLE *const table = tl->table; | |
| 351 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 573 times.
|
601 | if (!table->has_storage_handler()) { |
| 352 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if (setup_tmp_table_handler( |
| 353 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
30 | thd, table, |
| 354 | 30 | query_block->active_options() | TMP_TABLE_ALL_COLUMNS)) | |
| 355 | ✗ | return true; /* purecov: inspected */ | |
| 356 | } | ||
| 357 | |||
| 358 | 603 | table->file->stats.records = 2; | |
| 359 | } | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 9923683 times.
|
9923734 | if (thd->lex->using_hypergraph_optimizer) { |
| 364 | // The hypergraph optimizer also wants all subselect items to be optimized, | ||
| 365 | // so that it has cost information to attach to filter nodes. | ||
| 366 | 51 | for (Query_expression *unit = query_block->first_inner_query_expression(); | |
| 367 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 51 times.
|
58 | unit; unit = unit->next_query_expression()) { |
| 368 | // Derived tables and const subqueries are already optimized | ||
| 369 |
2/4✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
|
14 | if (!unit->is_optimized() && |
| 370 |
2/4✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
|
7 | unit->optimize(thd, /*materialize_destination=*/nullptr, |
| 371 | /*create_iterators=*/false, | ||
| 372 | /*finalize_access_paths=*/false)) | ||
| 373 | ✗ | return true; | |
| 374 | } | ||
| 375 | |||
| 376 | // The hypergraph optimizer does not do const tables, | ||
| 377 | // nor does it evaluate subqueries during optimization. | ||
| 378 | 51 | query_block->add_active_options(OPTION_NO_CONST_TABLES | | |
| 379 | OPTION_NO_SUBQUERY_DURING_OPTIMIZATION); | ||
| 380 | } | ||
| 381 | |||
| 382 | 9923713 | has_lateral = false; | |
| 383 | |||
| 384 | /* dump_TABLE_LIST_graph(query_block, query_block->leaf_tables); */ | ||
| 385 | |||
| 386 |
4/4✓ Branch 0 taken 9280299 times.
✓ Branch 1 taken 639385 times.
✓ Branch 2 taken 9273389 times.
✓ Branch 3 taken 6922 times.
|
9919689 | row_limit = ((select_distinct || !order.empty() || !group_list.empty()) |
| 387 |
2/2✓ Branch 0 taken 9919689 times.
✓ Branch 1 taken 4024 times.
|
19843413 | ? HA_POS_ERROR |
| 388 | 9273389 | : query_expression()->select_limit_cnt); | |
| 389 | // m_select_limit is used to decide if we are likely to scan the whole table. | ||
| 390 | 9923724 | m_select_limit = query_expression()->select_limit_cnt; | |
| 391 | |||
| 392 |
2/2✓ Branch 0 taken 180 times.
✓ Branch 1 taken 9923546 times.
|
9923725 | if (query_expression()->first_query_block()->active_options() & |
| 393 | OPTION_FOUND_ROWS) { | ||
| 394 | /* | ||
| 395 | Calculate found rows (ie., keep counting rows even after we hit LIMIT) if | ||
| 396 | - LIMIT is set, and | ||
| 397 | - This is the outermost query block (for a UNION query, this is the | ||
| 398 | fake query block that contains the limit applied on the final UNION | ||
| 399 | evaluation). | ||
| 400 | */ | ||
| 401 |
2/2✓ Branch 0 taken 121 times.
✓ Branch 1 taken 59 times.
|
301 | calc_found_rows = m_select_limit != HA_POS_ERROR && |
| 402 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 95 times.
|
121 | (!query_expression()->is_union() || |
| 403 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 14 times.
|
26 | query_block == query_expression()->fake_query_block); |
| 404 | } | ||
| 405 |
4/4✓ Branch 0 taken 9919740 times.
✓ Branch 1 taken 3986 times.
✓ Branch 2 taken 107 times.
✓ Branch 3 taken 9919633 times.
|
9923726 | if (having_cond || calc_found_rows) m_select_limit = HA_POS_ERROR; |
| 406 | |||
| 407 |
6/6✓ Branch 0 taken 231 times.
✓ Branch 1 taken 9923491 times.
✓ Branch 2 taken 213 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 213 times.
✓ Branch 5 taken 9923509 times.
|
9923726 | if (query_expression()->select_limit_cnt == 0 && !calc_found_rows) { |
| 408 | 213 | zero_result_cause = "Zero limit"; | |
| 409 | 213 | best_rowcount = 0; | |
| 410 |
1/2✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
|
213 | create_access_paths_for_zero_rows(); |
| 411 | 213 | goto setup_subq_exit; | |
| 412 | } | ||
| 413 | |||
| 414 |
4/4✓ Branch 0 taken 8599456 times.
✓ Branch 1 taken 1324053 times.
✓ Branch 2 taken 3963 times.
✓ Branch 3 taken 8595493 times.
|
9923509 | if (where_cond || query_block->outer_join) { |
| 415 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1327988 times.
|
1327998 | if (optimize_cond(thd, &where_cond, &cond_equal, |
| 416 |
1/2✓ Branch 0 taken 1327998 times.
✗ Branch 1 not taken.
|
1328016 | &query_block->top_join_list, &query_block->cond_value)) { |
| 417 | 10 | error = 1; | |
| 418 |
3/8✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
10 | DBUG_PRINT("error", ("Error from optimize_cond")); |
| 419 | 10 | return true; | |
| 420 | } | ||
| 421 |
2/2✓ Branch 0 taken 8197 times.
✓ Branch 1 taken 1319791 times.
|
1327988 | if (query_block->cond_value == Item::COND_FALSE) { |
| 422 | 8197 | zero_result_cause = "Impossible WHERE"; | |
| 423 | 8197 | best_rowcount = 0; | |
| 424 |
1/2✓ Branch 0 taken 8197 times.
✗ Branch 1 not taken.
|
8197 | create_access_paths_for_zero_rows(); |
| 425 | 8197 | goto setup_subq_exit; | |
| 426 | } | ||
| 427 | } | ||
| 428 |
2/2✓ Branch 0 taken 3968 times.
✓ Branch 1 taken 9911316 times.
|
9915284 | if (having_cond) { |
| 429 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3966 times.
|
3968 | if (optimize_cond(thd, &having_cond, &cond_equal, nullptr, |
| 430 |
1/2✓ Branch 0 taken 3968 times.
✗ Branch 1 not taken.
|
3968 | &query_block->having_value)) { |
| 431 | 2 | error = 1; | |
| 432 |
3/8✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
2 | DBUG_PRINT("error", ("Error from optimize_cond")); |
| 433 | 2 | return true; | |
| 434 | } | ||
| 435 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 3924 times.
|
3966 | if (query_block->having_value == Item::COND_FALSE) { |
| 436 | 42 | zero_result_cause = "Impossible HAVING"; | |
| 437 | 42 | best_rowcount = 0; | |
| 438 |
1/2✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
|
42 | create_access_paths_for_zero_rows(); |
| 439 | 42 | goto setup_subq_exit; | |
| 440 | } | ||
| 441 | } | ||
| 442 | |||
| 443 |
2/2✓ Branch 0 taken 9886191 times.
✓ Branch 1 taken 29049 times.
|
9915240 | if (thd->lex->sql_command == SQLCOM_INSERT_SELECT || |
| 444 |
2/2✓ Branch 0 taken 554 times.
✓ Branch 1 taken 9885637 times.
|
9886191 | thd->lex->sql_command == SQLCOM_REPLACE_SELECT) { |
| 445 | /* | ||
| 446 | Statement-based replication of INSERT ... SELECT ... LIMIT and | ||
| 447 | REPLACE ... SELECT is safe as order of row is defined with either | ||
| 448 | ORDER BY or other condition. However it is too late for it have | ||
| 449 | an impact to our decision to switch to row- based. We can only | ||
| 450 | suppress warning here. | ||
| 451 | */ | ||
| 452 |
1/2✓ Branch 0 taken 682 times.
✗ Branch 1 not taken.
|
682 | if (query_block->select_limit && query_block->select_limit->fixed && |
| 453 |
6/8✓ Branch 0 taken 682 times.
✓ Branch 1 taken 28921 times.
✓ Branch 2 taken 682 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 682 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 413 times.
✓ Branch 7 taken 29190 times.
|
30967 | query_block->select_limit->val_int() && |
| 454 |
3/4✓ Branch 0 taken 682 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 413 times.
✓ Branch 3 taken 269 times.
|
682 | !is_order_deterministic(&query_block->top_join_list, where_cond, |
| 455 | order.order)) { | ||
| 456 | 413 | thd->order_deterministic = false; | |
| 457 | } | ||
| 458 | } | ||
| 459 | |||
| 460 |
7/8✓ Branch 0 taken 19627 times.
✓ Branch 1 taken 9895613 times.
✓ Branch 2 taken 19627 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 19624 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 9915237 times.
|
9915240 | if (query_block->partitioned_table_count && prune_table_partitions()) { |
| 461 | 3 | error = 1; | |
| 462 |
3/8✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
3 | DBUG_PRINT("error", ("Error from prune_partitions")); |
| 463 | 3 | return true; | |
| 464 | } | ||
| 465 | |||
| 466 | /* | ||
| 467 | Try to optimize count(*), min() and max() to const fields if | ||
| 468 | there is implicit grouping (aggregate functions but no | ||
| 469 | group_list). In this case, the result set shall only contain one | ||
| 470 | row. | ||
| 471 | */ | ||
| 472 |
6/6✓ Branch 0 taken 1921742 times.
✓ Branch 1 taken 7993495 times.
✓ Branch 2 taken 430134 times.
✓ Branch 3 taken 1491608 times.
✓ Branch 4 taken 430096 times.
✓ Branch 5 taken 9485141 times.
|
10345371 | if (tables_list && implicit_grouping && |
| 473 |
2/2✓ Branch 0 taken 430096 times.
✓ Branch 1 taken 38 times.
|
430134 | !(query_block->active_options() & OPTION_NO_CONST_TABLES)) { |
| 474 | aggregate_evaluated outcome; | ||
| 475 |
3/4✓ Branch 0 taken 430096 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 430093 times.
|
430096 | if (optimize_aggregated_query(thd, query_block, *fields, where_cond, |
| 476 | &outcome)) { | ||
| 477 | 3 | error = 1; | |
| 478 |
3/8✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
3 | DBUG_PRINT("error", ("Error from optimize_aggregated_query")); |
| 479 | 3 | return true; | |
| 480 | } | ||
| 481 |
4/5✓ Branch 0 taken 405249 times.
✓ Branch 1 taken 15262 times.
✓ Branch 2 taken 5080 times.
✓ Branch 3 taken 4502 times.
✗ Branch 4 not taken.
|
430093 | switch (outcome) { |
| 482 | 405249 | case AGGR_REGULAR: | |
| 483 | // Query was not (fully) evaluated. Revert to regular optimization. | ||
| 484 | 405249 | break; | |
| 485 | 15262 | case AGGR_DELAYED: | |
| 486 | // Query was not (fully) evaluated. Revert to regular optimization, | ||
| 487 | // but indicate that storage engine supports HA_COUNT_ROWS_INSTANT. | ||
| 488 | 15262 | select_count = true; | |
| 489 | 15262 | break; | |
| 490 | 5080 | case AGGR_COMPLETE: { | |
| 491 | // All SELECT expressions are fully evaluated | ||
| 492 |
3/8✓ Branch 0 taken 5080 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5080 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5080 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
5080 | DBUG_PRINT("info", ("Select tables optimized away")); |
| 493 | 5080 | zero_result_cause = "Select tables optimized away"; | |
| 494 | 5080 | tables_list = nullptr; // All tables resolved | |
| 495 | 5080 | best_rowcount = 1; | |
| 496 | 5080 | const_tables = tables = primary_tables = query_block->leaf_table_count; | |
| 497 | AccessPath *path = | ||
| 498 | 5080 | NewFakeSingleRowAccessPath(thd, /*count_examined_rows=*/true); | |
| 499 |
1/2✓ Branch 0 taken 5080 times.
✗ Branch 1 not taken.
|
5080 | path = attach_access_paths_for_having_and_limit(path); |
| 500 | 5080 | m_root_access_path = path; | |
| 501 | /* | ||
| 502 | There are no relevant conditions left from the WHERE; | ||
| 503 | optimize_aggregated_query() will not return AGGR_COMPLETE if there are | ||
| 504 | any table-independent conditions, and all other conditions have been | ||
| 505 | optimized away by it. Thus, remove the condition, unless we have | ||
| 506 | EXPLAIN (in which case we will keep it for printing). | ||
| 507 | */ | ||
| 508 |
2/2✓ Branch 0 taken 4986 times.
✓ Branch 1 taken 94 times.
|
5080 | if (!thd->lex->is_explain()) { |
| 509 | #ifndef NDEBUG | ||
| 510 | // Verify, to be sure. | ||
| 511 |
2/2✓ Branch 0 taken 3250 times.
✓ Branch 1 taken 1736 times.
|
4986 | if (where_cond != nullptr) { |
| 512 | 6500 | Item *table_independent_conds = make_cond_for_table( | |
| 513 |
1/2✓ Branch 0 taken 3250 times.
✗ Branch 1 not taken.
|
3250 | thd, where_cond, PSEUDO_TABLE_BITS, table_map(0), |
| 514 | /*exclude_expensive_cond=*/true); | ||
| 515 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3250 times.
|
3250 | assert(table_independent_conds == nullptr); |
| 516 | } | ||
| 517 | #endif | ||
| 518 | 4986 | where_cond = nullptr; | |
| 519 | } | ||
| 520 | 9582 | goto setup_subq_exit; | |
| 521 | } | ||
| 522 | 4502 | case AGGR_EMPTY: | |
| 523 | // It was detected that the result tables are empty | ||
| 524 |
3/8✓ Branch 0 taken 4502 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4502 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4502 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
4502 | DBUG_PRINT("info", ("No matching min/max row")); |
| 525 | 4502 | zero_result_cause = "No matching min/max row"; | |
| 526 |
1/2✓ Branch 0 taken 4502 times.
✗ Branch 1 not taken.
|
4502 | create_access_paths_for_zero_rows(); |
| 527 | 4502 | goto setup_subq_exit; | |
| 528 | } | ||
| 529 | } | ||
| 530 |
2/2✓ Branch 0 taken 7993494 times.
✓ Branch 1 taken 1912158 times.
|
9905652 | if (tables_list == nullptr) { |
| 531 |
5/8✓ Branch 0 taken 7993499 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7993502 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 7993499 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
|
7993494 | DBUG_PRINT("info", ("No tables")); |
| 532 | 7993502 | best_rowcount = 1; | |
| 533 | 7993502 | error = 0; | |
| 534 |
3/4✓ Branch 0 taken 7993503 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 7993502 times.
|
7993502 | if (make_tmp_tables_info()) return true; |
| 535 |
1/2✓ Branch 0 taken 7993501 times.
✗ Branch 1 not taken.
|
7993502 | count_field_types(query_block, &tmp_table_param, *fields, false, false); |
| 536 | // Make plan visible for EXPLAIN | ||
| 537 |
1/2✓ Branch 0 taken 7993503 times.
✗ Branch 1 not taken.
|
7993501 | set_plan_state(NO_TABLES); |
| 538 |
1/2✓ Branch 0 taken 7993498 times.
✗ Branch 1 not taken.
|
7993503 | create_access_paths(); |
| 539 | 7993498 | return false; | |
| 540 | } | ||
| 541 | 1912158 | error = -1; // Error is sent to client | |
| 542 | |||
| 543 | { | ||
| 544 | 1912158 | m_windowing_steps = false; // initialization | |
| 545 | 1912158 | m_windows_sort = false; | |
| 546 |
1/2✓ Branch 0 taken 1912164 times.
✗ Branch 1 not taken.
|
1912158 | List_iterator<Window> li(m_windows); |
| 547 | Window *w; | ||
| 548 |
2/2✓ Branch 0 taken 1365 times.
✓ Branch 1 taken 1911269 times.
|
1912630 | while ((w = li++)) |
| 549 |
2/2✓ Branch 0 taken 899 times.
✓ Branch 1 taken 466 times.
|
1365 | if (w->needs_sorting()) { |
| 550 | 899 | m_windows_sort = true; | |
| 551 | 899 | break; | |
| 552 | } | ||
| 553 | } | ||
| 554 | |||
| 555 | 3824331 | sort_by_table = get_sort_by_table(order.order, group_list.order, | |
| 556 |
1/2✓ Branch 0 taken 1912163 times.
✗ Branch 1 not taken.
|
1912168 | query_block->leaf_tables); |
| 557 | |||
| 558 |
8/8✓ Branch 0 taken 606945 times.
✓ Branch 1 taken 1305218 times.
✓ Branch 2 taken 602636 times.
✓ Branch 3 taken 4309 times.
✓ Branch 4 taken 246046 times.
✓ Branch 5 taken 356591 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 1912167 times.
|
3467742 | if ((where_cond || !group_list.empty() || !order.empty()) && |
| 559 |
3/4✓ Branch 0 taken 1555579 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1555576 times.
|
1555573 | substitute_gc(thd, query_block, where_cond, group_list.order, |
| 560 | order.order)) { | ||
| 561 | // We added hidden fields to the all_fields list, count them. | ||
| 562 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | count_field_types(query_block, &tmp_table_param, query_block->fields, false, |
| 563 | false); | ||
| 564 | } | ||
| 565 | // Ensure there are no errors prior making query plan | ||
| 566 |
3/4✓ Branch 0 taken 1912173 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1912171 times.
|
1912170 | if (thd->is_error()) return true; |
| 567 | |||
| 568 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 1912125 times.
|
1912171 | if (thd->lex->using_hypergraph_optimizer) { |
| 569 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | Item *where_cond_no_in2exists = remove_in2exists_conds(thd, where_cond); |
| 570 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | Item *having_cond_no_in2exists = remove_in2exists_conds(thd, having_cond); |
| 571 | |||
| 572 | 46 | std::string trace_str; | |
| 573 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | std::string *trace_ptr = thd->opt_trace.is_started() ? &trace_str : nullptr; |
| 574 | |||
| 575 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | SaveCondEqualLists(cond_equal); |
| 576 | |||
| 577 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | m_root_access_path = FindBestQueryPlan(thd, query_block, trace_ptr); |
| 578 |
3/4✓ Branch 0 taken 39 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
|
46 | if (finalize_access_paths && m_root_access_path != nullptr) { |
| 579 |
2/4✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
|
39 | if (FinalizePlanForQueryBlock(thd, query_block)) { |
| 580 | ✗ | return true; | |
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 | // If this query block was modified by IN-to-EXISTS conversion, | ||
| 585 | // the outer query block may want to undo that conversion and materialize | ||
| 586 | // us instead, depending on cost. (Materialization has high initial cost, | ||
| 587 | // but looking up in the materialized table is typically cheaper than | ||
| 588 | // running the entire query.) If so, we will need to plan the query again, | ||
| 589 | // but with all extra conditions added by IN-to-EXISTS removed, as those | ||
| 590 | // are specific to the values referred to by the outer query. | ||
| 591 | // | ||
| 592 | // Thus, we detect this here, and plan a second query plan. There are | ||
| 593 | // computations that could be shared between the two plans (e.g. join order | ||
| 594 | // between tables for which there is no IN-to-EXISTS-related condition), | ||
| 595 | // so it is somewhat wasteful, but experiments have shown that planning | ||
| 596 | // both at the same time quickly clutters the code with such handling; | ||
| 597 | // there are so many places such filters could be added (base table filters, | ||
| 598 | // filters after various types of joins, join conditions, post-join filters, | ||
| 599 | // HAVING, possibly others) that trying to plan paths both with and without | ||
| 600 | // them incurs complexity that is not justified by the small computational | ||
| 601 | // gain it would bring. | ||
| 602 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | if (where_cond != where_cond_no_in2exists || |
| 603 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 39 times.
|
46 | having_cond != having_cond_no_in2exists) { |
| 604 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (trace_ptr != nullptr) { |
| 605 | *trace_ptr += | ||
| 606 | ✗ | "\nPlanning an alternative with in2exists conditions removed:\n"; | |
| 607 | } | ||
| 608 | 7 | where_cond = where_cond_no_in2exists; | |
| 609 | 7 | having_cond = having_cond_no_in2exists; | |
| 610 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | assert(!finalize_access_paths); |
| 611 | 7 | m_root_access_path_no_in2exists = | |
| 612 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | FindBestQueryPlan(thd, query_block, trace_ptr); |
| 613 | } else { | ||
| 614 | 39 | m_root_access_path_no_in2exists = nullptr; | |
| 615 | } | ||
| 616 | |||
| 617 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | if (trace != nullptr) { |
| 618 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | Opt_trace_object trace_wrapper2(&thd->opt_trace); |
| 619 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | Opt_trace_array join_optimizer(&thd->opt_trace, "join_optimizer"); |
| 620 | |||
| 621 | // Split by newlines. | ||
| 622 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | for (size_t pos = 0; pos < trace_str.size();) { |
| 623 | ✗ | size_t len = strcspn(trace_str.data() + pos, "\n"); | |
| 624 | ✗ | join_optimizer.add_utf8(trace_str.data() + pos, len); | |
| 625 | ✗ | pos += len + 1; | |
| 626 | } | ||
| 627 | 46 | } | |
| 628 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (m_root_access_path == nullptr) { |
| 629 | ✗ | return true; | |
| 630 | } | ||
| 631 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | set_plan_state(PLAN_READY); |
| 632 |
2/4✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
|
46 | DEBUG_SYNC(thd, "after_join_optimize"); |
| 633 | 46 | return false; | |
| 634 | 46 | } | |
| 635 | |||
| 636 | // ---------------------------------------------------------------------------- | ||
| 637 | // All of this is never called for the hypergraph join optimizer! | ||
| 638 | // ---------------------------------------------------------------------------- | ||
| 639 | |||
| 640 | // Set up join order and initial access paths | ||
| 641 |
1/2✓ Branch 0 taken 1912122 times.
✗ Branch 1 not taken.
|
1912125 | THD_STAGE_INFO(thd, stage_statistics); |
| 642 |
3/4✓ Branch 0 taken 1912122 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 1911996 times.
|
1912122 | if (make_join_plan()) { |
| 643 |
3/4✓ Branch 0 taken 17 times.
✓ Branch 1 taken 109 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
126 | if (thd->killed) thd->send_kill_message(); |
| 644 |
3/8✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 126 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
126 | DBUG_PRINT("error", ("Error: JOIN::make_join_plan() failed")); |
| 645 | 126 | return true; | |
| 646 | } | ||
| 647 | |||
| 648 | // At this stage, join_tab==NULL, JOIN_TABs are listed in order by best_ref. | ||
| 649 |
4/6✓ Branch 0 taken 1911982 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 1911989 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1911991 times.
✗ Branch 5 not taken.
|
1911996 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 650 | |||
| 651 |
2/2✓ Branch 0 taken 8537 times.
✓ Branch 1 taken 1903468 times.
|
1912005 | if (zero_result_cause != nullptr) { // Can be set by make_join_plan(). |
| 652 |
1/2✓ Branch 0 taken 8537 times.
✗ Branch 1 not taken.
|
8537 | create_access_paths_for_zero_rows(); |
| 653 | 8537 | goto setup_subq_exit; | |
| 654 | } | ||
| 655 | |||
| 656 |
2/2✓ Branch 0 taken 1903120 times.
✓ Branch 1 taken 348 times.
|
1903468 | if (rollup_state == RollupState::NONE) { |
| 657 | /* Remove distinct if only const tables */ | ||
| 658 | 1903120 | select_distinct &= !plan_is_const(); | |
| 659 | } | ||
| 660 | |||
| 661 |
6/6✓ Branch 0 taken 90938 times.
✓ Branch 1 taken 1812536 times.
✓ Branch 2 taken 87545 times.
✓ Branch 3 taken 3393 times.
✓ Branch 4 taken 85676 times.
✓ Branch 5 taken 1817798 times.
|
1991019 | if (const_tables && !thd->locked_tables_mode && |
| 662 |
2/2✓ Branch 0 taken 85676 times.
✓ Branch 1 taken 1869 times.
|
87545 | !(query_block->active_options() & SELECT_NO_UNLOCK)) { |
| 663 | TABLE *ct[MAX_TABLES]; | ||
| 664 |
2/2✓ Branch 0 taken 86796 times.
✓ Branch 1 taken 85677 times.
|
172473 | for (uint i = 0; i < const_tables; i++) { |
| 665 | 86796 | ct[i] = best_ref[i]->table(); | |
| 666 |
1/2✓ Branch 0 taken 86797 times.
✗ Branch 1 not taken.
|
86796 | ct[i]->file->ha_index_or_rnd_end(); |
| 667 | } | ||
| 668 |
1/2✓ Branch 0 taken 85677 times.
✗ Branch 1 not taken.
|
85677 | mysql_unlock_some_tables(thd, ct, const_tables); |
| 669 | } | ||
| 670 |
4/4✓ Branch 0 taken 604640 times.
✓ Branch 1 taken 1298835 times.
✓ Branch 2 taken 4080 times.
✓ Branch 3 taken 600560 times.
|
1903475 | if (!where_cond && query_block->outer_join) { |
| 671 | /* Handle the case where we have an OUTER JOIN without a WHERE */ | ||
| 672 |
1/2✓ Branch 0 taken 4080 times.
✗ Branch 1 not taken.
|
8160 | where_cond = new Item_func_true(); // Always true |
| 673 | } | ||
| 674 | |||
| 675 | 1903475 | error = 0; | |
| 676 | /* | ||
| 677 | Among the equal fields belonging to the same multiple equality | ||
| 678 | choose the one that is to be retrieved first and substitute | ||
| 679 | all references to these in where condition for a reference for | ||
| 680 | the selected field. | ||
| 681 | */ | ||
| 682 |
2/2✓ Branch 0 taken 1302883 times.
✓ Branch 1 taken 600592 times.
|
1903475 | if (where_cond) { |
| 683 | 1302900 | where_cond = | |
| 684 |
1/2✓ Branch 0 taken 1302900 times.
✗ Branch 1 not taken.
|
1302883 | substitute_for_best_equal_field(thd, where_cond, cond_equal, map2table); |
| 685 |
2/4✓ Branch 0 taken 1302900 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1302900 times.
|
1302900 | if (thd->is_error()) { |
| 686 | ✗ | error = 1; | |
| 687 | ✗ | DBUG_PRINT("error", ("Error from substitute_for_best_equal")); | |
| 688 | ✗ | return true; | |
| 689 | } | ||
| 690 |
1/2✓ Branch 0 taken 1302899 times.
✗ Branch 1 not taken.
|
1302900 | where_cond->update_used_tables(); |
| 691 |
3/6✓ Branch 0 taken 1302900 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1302894 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1302899 | DBUG_EXECUTE("where", |
| 692 | print_where(thd, where_cond, "after substitute_best_equal", | ||
| 693 | QT_ORDINARY);); | ||
| 694 | } | ||
| 695 | |||
| 696 | /* | ||
| 697 | Perform the same optimization on field evaluation for all join conditions. | ||
| 698 | */ | ||
| 699 |
2/2✓ Branch 0 taken 6384958 times.
✓ Branch 1 taken 1903453 times.
|
8288411 | for (uint i = const_tables; i < tables; ++i) { |
| 700 | 6384958 | JOIN_TAB *const tab = best_ref[i]; | |
| 701 |
6/6✓ Branch 0 taken 3826540 times.
✓ Branch 1 taken 2558433 times.
✓ Branch 2 taken 403550 times.
✓ Branch 3 taken 3423000 times.
✓ Branch 4 taken 403550 times.
✓ Branch 5 taken 5981433 times.
|
6384958 | if (tab->position() && tab->join_cond()) { |
| 702 | 807097 | tab->set_join_cond(substitute_for_best_equal_field( | |
| 703 |
1/2✓ Branch 0 taken 403547 times.
✗ Branch 1 not taken.
|
403550 | thd, tab->join_cond(), tab->cond_equal, map2table)); |
| 704 |
2/4✓ Branch 0 taken 403544 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 403544 times.
|
403545 | if (thd->is_error()) { |
| 705 | ✗ | error = 1; | |
| 706 | ✗ | DBUG_PRINT("error", ("Error from substitute_for_best_equal")); | |
| 707 | ✗ | return true; | |
| 708 | } | ||
| 709 |
1/2✓ Branch 0 taken 403550 times.
✗ Branch 1 not taken.
|
403544 | tab->join_cond()->update_used_tables(); |
| 710 |
1/2✓ Branch 0 taken 403549 times.
✗ Branch 1 not taken.
|
403550 | if (tab->join_cond()) |
| 711 |
1/2✓ Branch 0 taken 403521 times.
✗ Branch 1 not taken.
|
403549 | tab->join_cond()->walk(&Item::cast_incompatible_args, |
| 712 | enum_walk::POSTFIX, nullptr); | ||
| 713 | } | ||
| 714 | } | ||
| 715 | |||
| 716 |
3/4✓ Branch 0 taken 1903461 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1903458 times.
|
1903453 | if (init_ref_access()) { |
| 717 | 3 | error = 1; | |
| 718 |
3/8✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
3 | DBUG_PRINT("error", ("Error from init_ref_access")); |
| 719 | 3 | return true; | |
| 720 | } | ||
| 721 | |||
| 722 | // Update table dependencies after assigning ref access fields | ||
| 723 |
1/2✓ Branch 0 taken 1903453 times.
✗ Branch 1 not taken.
|
1903458 | update_depend_map(); |
| 724 | |||
| 725 |
1/2✓ Branch 0 taken 1903457 times.
✗ Branch 1 not taken.
|
1903453 | THD_STAGE_INFO(thd, stage_preparing); |
| 726 | |||
| 727 |
3/4✓ Branch 0 taken 1903449 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2920 times.
✓ Branch 3 taken 1900529 times.
|
1903457 | if (make_join_query_block(this, where_cond)) { |
| 728 |
3/4✓ Branch 0 taken 2921 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2919 times.
|
2920 | if (thd->is_error()) return true; |
| 729 | |||
| 730 | 2919 | zero_result_cause = "Impossible WHERE noticed after reading const tables"; | |
| 731 |
1/2✓ Branch 0 taken 2918 times.
✗ Branch 1 not taken.
|
2919 | create_access_paths_for_zero_rows(); |
| 732 | 2918 | goto setup_subq_exit; | |
| 733 | } | ||
| 734 | |||
| 735 | // Inject cast nodes into the WHERE conditions | ||
| 736 |
2/2✓ Branch 0 taken 1218968 times.
✓ Branch 1 taken 681561 times.
|
1900529 | if (where_cond) |
| 737 |
1/2✓ Branch 0 taken 1218970 times.
✗ Branch 1 not taken.
|
1218968 | where_cond->walk(&Item::cast_incompatible_args, enum_walk::POSTFIX, |
| 738 | nullptr); | ||
| 739 | |||
| 740 | 1900531 | error = -1; /* if goto err */ | |
| 741 | |||
| 742 |
2/4✓ Branch 0 taken 1900538 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1900538 times.
|
1900531 | if (optimize_distinct_group_order()) return true; |
| 743 | |||
| 744 |
4/4✓ Branch 0 taken 1845139 times.
✓ Branch 1 taken 55396 times.
✓ Branch 2 taken 57688 times.
✓ Branch 3 taken 1842847 times.
|
3745677 | if ((query_block->active_options() & SELECT_NO_JOIN_CACHE) || |
| 745 |
2/2✓ Branch 0 taken 2290 times.
✓ Branch 1 taken 1842849 times.
|
1845139 | query_block->ftfunc_list->elements) |
| 746 | 57688 | no_jbuf_after = 0; | |
| 747 | |||
| 748 | /* Perform FULLTEXT search before all regular searches */ | ||
| 749 |
7/8✓ Branch 0 taken 2294 times.
✓ Branch 1 taken 1898242 times.
✓ Branch 2 taken 2293 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 2290 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 1900532 times.
|
1900535 | if (query_block->has_ft_funcs() && optimize_fts_query()) return true; |
| 750 | |||
| 751 | /* | ||
| 752 | By setting child_subquery_can_materialize so late we gain the following: | ||
| 753 | JOIN::compare_costs_of_subquery_strategies() can test this variable to | ||
| 754 | know if we are have finished evaluating constant conditions, which itself | ||
| 755 | helps determining fanouts. | ||
| 756 | */ | ||
| 757 | 1900532 | child_subquery_can_materialize = true; | |
| 758 | |||
| 759 | /* | ||
| 760 | It's necessary to check const part of HAVING cond as | ||
| 761 | there is a chance that some cond parts may become | ||
| 762 | const items after make_join_plan() (for example | ||
| 763 | when Item is a reference to const table field from | ||
| 764 | outer join). | ||
| 765 | This check is performed only for those conditions | ||
| 766 | which do not use aggregate functions. In such case | ||
| 767 | temporary table may not be used and const condition | ||
| 768 | elements may be lost during further having | ||
| 769 | condition transformation in JOIN::exec. | ||
| 770 | */ | ||
| 771 |
8/8✓ Branch 0 taken 3554 times.
✓ Branch 1 taken 1896978 times.
✓ Branch 2 taken 851 times.
✓ Branch 3 taken 2703 times.
✓ Branch 4 taken 26 times.
✓ Branch 5 taken 825 times.
✓ Branch 6 taken 26 times.
✓ Branch 7 taken 1900506 times.
|
1900532 | if (having_cond && !having_cond->has_aggregation() && (const_tables > 0)) { |
| 772 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | having_cond->update_used_tables(); |
| 773 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if (remove_eq_conds(thd, having_cond, &having_cond, |
| 774 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | &query_block->having_value)) { |
| 775 | ✗ | error = 1; | |
| 776 | ✗ | DBUG_PRINT("error", ("Error from remove_eq_conds")); | |
| 777 | ✗ | return true; | |
| 778 | } | ||
| 779 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 19 times.
|
26 | if (query_block->having_value == Item::COND_FALSE) { |
| 780 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
14 | having_cond = new Item_func_false(); |
| 781 | 7 | zero_result_cause = | |
| 782 | "Impossible HAVING noticed after reading const tables"; | ||
| 783 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | create_access_paths_for_zero_rows(); |
| 784 | 7 | goto setup_subq_exit; | |
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 788 | // Inject cast nodes into the HAVING conditions | ||
| 789 |
2/2✓ Branch 0 taken 3543 times.
✓ Branch 1 taken 1896982 times.
|
1900525 | if (having_cond) |
| 790 |
1/2✓ Branch 0 taken 3543 times.
✗ Branch 1 not taken.
|
3543 | having_cond->walk(&Item::cast_incompatible_args, enum_walk::POSTFIX, |
| 791 | nullptr); | ||
| 792 | |||
| 793 | // Traverse the expressions and inject cast nodes to compatible data types, | ||
| 794 | // if needed. | ||
| 795 |
7/12✓ Branch 0 taken 1900514 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1900526 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8702409 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8702413 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 10602935 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8702406 times.
✓ Branch 11 taken 1900529 times.
|
10602938 | for (Item *item : *fields) { |
| 796 |
1/2✓ Branch 0 taken 8702413 times.
✗ Branch 1 not taken.
|
8702409 | item->walk(&Item::cast_incompatible_args, enum_walk::POSTFIX, nullptr); |
| 797 | } | ||
| 798 | |||
| 799 | // Also GROUP BY expressions, so that find_in_group_list() doesn't | ||
| 800 | // inadvertently fail because the SELECT list has casts that GROUP BY doesn't. | ||
| 801 |
2/2✓ Branch 0 taken 19318 times.
✓ Branch 1 taken 1900529 times.
|
1919847 | for (ORDER *ord = group_list.order; ord != nullptr; ord = ord->next) { |
| 802 | 19318 | (*ord->item) | |
| 803 |
1/2✓ Branch 0 taken 19318 times.
✗ Branch 1 not taken.
|
19318 | ->walk(&Item::cast_incompatible_args, enum_walk::POSTFIX, nullptr); |
| 804 | } | ||
| 805 | |||
| 806 |
2/2✓ Branch 0 taken 332 times.
✓ Branch 1 taken 1900197 times.
|
1900529 | if (rollup_state != RollupState::NONE) { |
| 807 | /* | ||
| 808 | Fields may have been replaced by Item_rollup_group_item, so | ||
| 809 | recalculate the number of fields and functions for this query block. | ||
| 810 | */ | ||
| 811 | |||
| 812 | // JOIN::optimize_rollup() may set allow_group_via_temp_table = false, | ||
| 813 | // and we must not undo that. | ||
| 814 | 332 | const bool save_allow_group_via_temp_table = | |
| 815 | tmp_table_param.allow_group_via_temp_table; | ||
| 816 | |||
| 817 |
1/2✓ Branch 0 taken 332 times.
✗ Branch 1 not taken.
|
332 | count_field_types(query_block, &tmp_table_param, *fields, false, false); |
| 818 | 332 | tmp_table_param.allow_group_via_temp_table = | |
| 819 | save_allow_group_via_temp_table; | ||
| 820 | } | ||
| 821 | |||
| 822 | // See if this subquery can be evaluated with subselect_indexsubquery_engine | ||
| 823 |
3/4✓ Branch 0 taken 1900529 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 147 times.
✓ Branch 3 taken 1900382 times.
|
1900529 | if (const int ret = replace_index_subquery()) { |
| 824 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 147 times.
|
147 | if (ret == -1) { |
| 825 | // Error (e.g. allocation failed, or some condition was attempted | ||
| 826 | // evaluated statically and failed). | ||
| 827 | ✗ | return true; | |
| 828 | } | ||
| 829 | |||
| 830 |
1/2✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
|
147 | create_access_paths_for_index_subquery(); |
| 831 |
1/2✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
|
147 | set_plan_state(PLAN_READY); |
| 832 | /* | ||
| 833 | We leave optimize() because the rest of it is only about order/group | ||
| 834 | which those subqueries don't have and about setting up plan which | ||
| 835 | we're not going to use due to different execution method. | ||
| 836 | */ | ||
| 837 | 147 | return false; | |
| 838 | } | ||
| 839 | |||
| 840 | { | ||
| 841 | /* | ||
| 842 | If the hint FORCE INDEX FOR ORDER BY/GROUP BY is used for the first | ||
| 843 | table (it does not make sense for other tables) then we cannot do join | ||
| 844 | buffering. | ||
| 845 | */ | ||
| 846 |
2/2✓ Branch 0 taken 1813737 times.
✓ Branch 1 taken 86644 times.
|
1900382 | if (!plan_is_const()) { |
| 847 | 1813737 | const TABLE *const first = best_ref[const_tables]->table(); | |
| 848 |
6/6✓ Branch 0 taken 126595 times.
✓ Branch 1 taken 1687142 times.
✓ Branch 2 taken 125027 times.
✓ Branch 3 taken 1556 times.
✓ Branch 4 taken 1568 times.
✓ Branch 5 taken 1812157 times.
|
3625906 | if ((first->force_index_order && !order.empty()) || |
| 849 |
4/4✓ Branch 0 taken 125033 times.
✓ Branch 1 taken 1687136 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 125021 times.
|
1812169 | (first->force_index_group && !group_list.empty())) |
| 850 | 1568 | no_jbuf_after = 0; | |
| 851 | } | ||
| 852 | |||
| 853 | 1900369 | bool simple_sort = true; | |
| 854 | 1900369 | Table_map_restorer deps_lateral(&deps_of_remaining_lateral_derived_tables); | |
| 855 | // Check whether join cache could be used | ||
| 856 |
2/2✓ Branch 0 taken 6381384 times.
✓ Branch 1 taken 1900397 times.
|
8281781 | for (uint i = const_tables; i < tables; i++) { |
| 857 | 6381384 | JOIN_TAB *const tab = best_ref[i]; | |
| 858 |
2/2✓ Branch 0 taken 2555097 times.
✓ Branch 1 taken 3826299 times.
|
6381384 | if (!tab->position()) continue; |
| 859 |
2/4✓ Branch 0 taken 3826295 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3826295 times.
|
3826299 | if (setup_join_buffering(tab, this, no_jbuf_after)) return true; |
| 860 |
2/2✓ Branch 0 taken 120240 times.
✓ Branch 1 taken 3706058 times.
|
3826295 | if (tab->use_join_cache() != JOIN_CACHE::ALG_NONE) simple_sort = false; |
| 861 |
3/4✓ Branch 0 taken 2131 times.
✓ Branch 1 taken 3824182 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2134 times.
|
3826298 | assert(tab->type() != JT_FT || |
| 862 | tab->use_join_cache() == JOIN_CACHE::ALG_NONE); | ||
| 863 |
6/6✓ Branch 0 taken 2154 times.
✓ Branch 1 taken 3824162 times.
✓ Branch 2 taken 562 times.
✓ Branch 3 taken 1592 times.
✓ Branch 4 taken 562 times.
✓ Branch 5 taken 3825754 times.
|
3826316 | if (has_lateral && get_lateral_deps(*best_ref[i]) != 0) { |
| 864 | 562 | deps_of_remaining_lateral_derived_tables = | |
| 865 |
1/2✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
|
562 | calculate_deps_of_remaining_lateral_derived_tables(all_table_map, |
| 866 | i + 1); | ||
| 867 | } | ||
| 868 | } | ||
| 869 |
2/2✓ Branch 0 taken 104354 times.
✓ Branch 1 taken 1796043 times.
|
1900397 | if (!simple_sort) { |
| 870 | /* | ||
| 871 | A join buffer is used for this table. We here inform the optimizer | ||
| 872 | that it should not rely on rows of the first non-const table being in | ||
| 873 | order thanks to an index scan; indeed join buffering of the present | ||
| 874 | table subsequently changes the order of rows. | ||
| 875 | */ | ||
| 876 | 104354 | simple_order = simple_group = false; | |
| 877 | } | ||
| 878 |
1/2✓ Branch 0 taken 1900382 times.
✗ Branch 1 not taken.
|
1900397 | } |
| 879 | |||
| 880 |
6/6✓ Branch 0 taken 1813739 times.
✓ Branch 1 taken 86643 times.
✓ Branch 2 taken 629579 times.
✓ Branch 3 taken 1184160 times.
✓ Branch 4 taken 629579 times.
✓ Branch 5 taken 1270803 times.
|
1900382 | if (!plan_is_const() && !order.empty()) { |
| 881 | /* | ||
| 882 | Force using of tmp table if sorting by a SP or UDF function due to | ||
| 883 | their expensive and probably non-deterministic nature. | ||
| 884 | */ | ||
| 885 |
2/2✓ Branch 0 taken 982026 times.
✓ Branch 1 taken 629527 times.
|
1611553 | for (ORDER *tmp_order = order.order; tmp_order; |
| 886 | 981974 | tmp_order = tmp_order->next) { | |
| 887 | 982026 | Item *item = *tmp_order->item; | |
| 888 |
3/4✓ Branch 0 taken 982024 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 981974 times.
|
982026 | if (item->is_expensive()) { |
| 889 | /* Force tmp table without sort */ | ||
| 890 | 50 | simple_order = simple_group = false; | |
| 891 | 50 | break; | |
| 892 | } | ||
| 893 | } | ||
| 894 | } | ||
| 895 | |||
| 896 | /* | ||
| 897 | Check if we need to create a temporary table prior to any windowing. | ||
| 898 | |||
| 899 | (1) If there is ROLLUP, which happens before DISTINCT, windowing and ORDER | ||
| 900 | BY, any of those clauses needs the result of ROLLUP in a tmp table. | ||
| 901 | |||
| 902 | Rows which ROLLUP adds to the result are visible only to DISTINCT, | ||
| 903 | windowing and ORDER BY which we handled above. So for the rest of | ||
| 904 | conditions ((2), etc), we can do as if there were no ROLLUP. | ||
| 905 | |||
| 906 | (2) If all tables are constant, the query's result is guaranteed to have 0 | ||
| 907 | or 1 row only, so all SQL clauses discussed below (DISTINCT, ORDER BY, | ||
| 908 | GROUP BY, windowing, SQL_BUFFER_RESULT) are useless and need no tmp | ||
| 909 | table. | ||
| 910 | |||
| 911 | (3) If there is GROUP BY which isn't resolved by using an index or sorting | ||
| 912 | the first table, we need a tmp table to compute the grouped rows. | ||
| 913 | GROUP BY happens before windowing; so it is a pre-windowing tmp | ||
| 914 | table. | ||
| 915 | |||
| 916 | (4) (5) If there is DISTINCT, or ORDER BY which isn't resolved by using an | ||
| 917 | index or sorting the first table, those clauses need an input tmp table. | ||
| 918 | If we have windowing, as those clauses are used after windowing, they can | ||
| 919 | use the last window's tmp table. | ||
| 920 | |||
| 921 | (6) If there are different ORDER BY and GROUP BY orders, ORDER BY needs an | ||
| 922 | input tmp table, so it's like (5). | ||
| 923 | |||
| 924 | (7) If the user wants us to buffer the result, we need a tmp table. But | ||
| 925 | windowing creates one anyway, and so does the materialization of a derived | ||
| 926 | table. | ||
| 927 | |||
| 928 | See also the computation of Window::m_short_circuit, | ||
| 929 | where we make sure to create a tmp table if the clauses above want one. | ||
| 930 | |||
| 931 | (8) If the first windowing step needs sorting, filesort() will be used; it | ||
| 932 | can sort one table but not a join of tables, so we need a tmp table | ||
| 933 | then. If GROUP BY was optimized away, the pre-windowing result is 0 or 1 | ||
| 934 | row so doesn't need sorting. | ||
| 935 | */ | ||
| 936 | |||
| 937 |
4/4✓ Branch 0 taken 332 times.
✓ Branch 1 taken 1900048 times.
✓ Branch 2 taken 112 times.
✓ Branch 3 taken 1900268 times.
|
1900712 | if (rollup_state != RollupState::NONE && // (1) |
| 938 |
6/6✓ Branch 0 taken 292 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 256 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 220 times.
|
332 | (select_distinct || has_windows || !order.empty())) |
| 939 | 112 | need_tmp_before_win = true; | |
| 940 | |||
| 941 | /* | ||
| 942 | If we have full-text columns involved in aggregation, we need to | ||
| 943 | materialize it, as the saving and loading of rows in AggregateIterator | ||
| 944 | does not include FTS information. If we have multiple tables, we'll | ||
| 945 | have a materialization (either because we're aggregating into a temporary | ||
| 946 | table, or because we always materialize before further operations), | ||
| 947 | and if we have a GROUP BY, we'll either have an aggregate-to-table | ||
| 948 | or a sort, which also fixes the issue. However, in the case of a single | ||
| 949 | table and implicit grouping, we need to force the temporary table here. | ||
| 950 | */ | ||
| 951 |
2/2✓ Branch 0 taken 417408 times.
✓ Branch 1 taken 1482847 times.
|
1900255 | if (!need_tmp_before_win && implicit_grouping && |
| 952 |
9/10✓ Branch 0 taken 1900255 times.
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 353574 times.
✓ Branch 3 taken 63834 times.
✓ Branch 4 taken 353591 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 82 times.
✓ Branch 7 taken 353492 times.
✓ Branch 8 taken 82 times.
✓ Branch 9 taken 1900281 times.
|
4154209 | primary_tables - const_tables == 1 && order.empty() && |
| 953 | 353591 | best_ref[const_tables]->table_ref->is_fulltext_searched()) { | |
| 954 |
8/14✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 82 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 82 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 82 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 80 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 162 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 82 times.
✓ Branch 13 taken 80 times.
|
162 | for (Item *item : VisibleFields(*fields)) { |
| 955 | 82 | need_tmp_before_win |= | |
| 956 |
1/2✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
|
82 | contains_function_of_type(item, Item_func::FT_FUNC); |
| 957 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 80 times.
|
82 | if (need_tmp_before_win) break; |
| 958 | } | ||
| 959 | } | ||
| 960 | |||
| 961 |
2/2✓ Branch 0 taken 1813718 times.
✓ Branch 1 taken 86637 times.
|
1900363 | if (!plan_is_const()) // (2) |
| 962 | { | ||
| 963 |
2/2✓ Branch 0 taken 10273 times.
✓ Branch 1 taken 1569 times.
|
1825560 | if ((!group_list.empty() && !simple_group) || // (3) |
| 964 |
4/4✓ Branch 0 taken 1811077 times.
✓ Branch 1 taken 1078 times.
✓ Branch 2 taken 1810048 times.
✓ Branch 3 taken 1029 times.
|
1812155 | (!has_windows && (select_distinct || // (4) |
| 965 |
4/4✓ Branch 0 taken 628659 times.
✓ Branch 1 taken 1181386 times.
✓ Branch 2 taken 357402 times.
✓ Branch 3 taken 271257 times.
|
1810048 | (!order.empty() && !simple_order) || // (5) |
| 966 |
4/4✓ Branch 0 taken 9910 times.
✓ Branch 1 taken 1528885 times.
✓ Branch 2 taken 9773 times.
✓ Branch 3 taken 137 times.
|
1538788 | (!group_list.empty() && !order.empty()))) || // (6) |
| 967 |
2/2✓ Branch 0 taken 7056 times.
✓ Branch 1 taken 1532678 times.
|
1539737 | ((query_block->active_options() & OPTION_BUFFER_RESULT) && |
| 968 |
1/2✓ Branch 0 taken 7056 times.
✗ Branch 1 not taken.
|
7056 | !has_windows && |
| 969 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7049 times.
|
7056 | !(query_expression()->derived_table && |
| 970 | 7 | query_expression() | |
| 971 |
8/8✓ Branch 0 taken 11842 times.
✓ Branch 1 taken 1801882 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 1078 times.
✓ Branch 5 taken 1531602 times.
✓ Branch 6 taken 281063 times.
✓ Branch 7 taken 1532662 times.
|
3628527 | ->derived_table->uses_materialization())) || // (7) |
| 972 |
4/4✓ Branch 0 taken 18 times.
✓ Branch 1 taken 1060 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 5 times.
|
1096 | (has_windows && (primary_tables - const_tables) > 1 && // (8) |
| 973 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
31 | m_windows[0]->needs_sorting() && !group_optimized_away)) |
| 974 | 281063 | need_tmp_before_win = true; | |
| 975 | } | ||
| 976 | |||
| 977 |
4/6✓ Branch 0 taken 1900374 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 1900347 times.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
|
1900362 | DBUG_EXECUTE("info", TEST_join(this);); |
| 978 | |||
| 979 |
2/4✓ Branch 0 taken 1900377 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1900377 times.
|
1900374 | if (alloc_qep(tables)) return (error = 1); /* purecov: inspected */ |
| 980 | |||
| 981 |
2/2✓ Branch 0 taken 1813734 times.
✓ Branch 1 taken 86643 times.
|
1900377 | if (!plan_is_const()) { |
| 982 | // Test if we can use an index instead of sorting | ||
| 983 |
1/2✓ Branch 0 taken 1813737 times.
✗ Branch 1 not taken.
|
1813734 | test_skip_sort(); |
| 984 | |||
| 985 |
3/4✓ Branch 0 taken 1813723 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1813722 times.
|
1813737 | if (finalize_table_conditions()) return true; |
| 986 | } | ||
| 987 | |||
| 988 |
2/4✓ Branch 0 taken 1900381 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1900381 times.
|
1900365 | if (make_join_readinfo(this, no_jbuf_after)) |
| 989 | ✗ | return true; /* purecov: inspected */ | |
| 990 | |||
| 991 |
3/4✓ Branch 0 taken 1900380 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1900379 times.
|
1900381 | if (make_tmp_tables_info()) return true; |
| 992 | |||
| 993 | /* | ||
| 994 | If we decided to not sort after all, update the cost of the JOIN. | ||
| 995 | Windowing sorts are handled elsewhere | ||
| 996 | */ | ||
| 997 |
4/4✓ Branch 0 taken 440286 times.
✓ Branch 1 taken 1460093 times.
✓ Branch 2 taken 20888 times.
✓ Branch 3 taken 1879491 times.
|
2340665 | if (sort_cost > 0.0 && |
| 998 |
2/2✓ Branch 0 taken 20888 times.
✓ Branch 1 taken 419398 times.
|
440286 | !explain_flags.any(ESP_USING_FILESORT, ESC_WINDOWING)) { |
| 999 | 20888 | best_read -= sort_cost; | |
| 1000 | 20888 | sort_cost = 0.0; | |
| 1001 | } | ||
| 1002 | |||
| 1003 |
1/2✓ Branch 0 taken 1900379 times.
✗ Branch 1 not taken.
|
1900379 | count_field_types(query_block, &tmp_table_param, *fields, false, false); |
| 1004 | |||
| 1005 |
1/2✓ Branch 0 taken 1900363 times.
✗ Branch 1 not taken.
|
1900379 | create_access_paths(); |
| 1006 | |||
| 1007 | // Creating iterators may evaluate a constant hash join condition, which may | ||
| 1008 | // fail: | ||
| 1009 |
2/4✓ Branch 0 taken 1900373 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1900373 times.
|
1900363 | if (thd->is_error()) return true; |
| 1010 | |||
| 1011 | /* | ||
| 1012 | At this stage, we have set up an AccessPath 'plan'. Traverse the | ||
| 1013 | AccessPath structures and find components which may be offloaded to | ||
| 1014 | the engines. This process is allowed to modify the AccessPath itself. | ||
| 1015 | (Removing/modifying FILTERs where pushed to the engines, change JOIN* | ||
| 1016 | algorithms being used, modify aggregate expressions, ...). | ||
| 1017 | This will later affects which type of Iterator we should create. Thus no | ||
| 1018 | Iterators should be set up until after push_to_engines() has completed. | ||
| 1019 | |||
| 1020 | Note that when the Hypergraph optimizer is used, there is an entirely | ||
| 1021 | different code path to push_to_engine(). (We create the AcccesPath directly | ||
| 1022 | instead of converting the QEP_TABs into an AccessPath structure). | ||
| 1023 | In the HG case we push_to_engine() when FinalizePlanForQueryBlock() | ||
| 1024 | has finalized the 'plan'. | ||
| 1025 | */ | ||
| 1026 |
2/4✓ Branch 0 taken 1900369 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1900369 times.
|
1900373 | if (push_to_engines()) return true; |
| 1027 | |||
| 1028 | // Make plan visible for EXPLAIN | ||
| 1029 |
1/2✓ Branch 0 taken 1900378 times.
✗ Branch 1 not taken.
|
1900369 | set_plan_state(PLAN_READY); |
| 1030 | |||
| 1031 |
3/4✓ Branch 0 taken 1892149 times.
✓ Branch 1 taken 8224 times.
✓ Branch 2 taken 1892156 times.
✗ Branch 3 not taken.
|
1900378 | DEBUG_SYNC(thd, "after_join_optimize"); |
| 1032 | |||
| 1033 | 1900380 | error = 0; | |
| 1034 | 1900380 | return false; | |
| 1035 | |||
| 1036 | 29496 | setup_subq_exit: | |
| 1037 | |||
| 1038 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29496 times.
|
29496 | assert(zero_result_cause != nullptr); |
| 1039 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29496 times.
|
29496 | assert(m_root_access_path != nullptr); |
| 1040 | /* | ||
| 1041 | Even with zero matching rows, subqueries in the HAVING clause may | ||
| 1042 | need to be evaluated if there are aggregate functions in the | ||
| 1043 | query. If this JOIN is part of an outer query, subqueries in HAVING may | ||
| 1044 | be evaluated several times in total; so subquery materialization makes | ||
| 1045 | sense. | ||
| 1046 | */ | ||
| 1047 | 29496 | child_subquery_can_materialize = true; | |
| 1048 | |||
| 1049 |
1/2✓ Branch 0 taken 29497 times.
✗ Branch 1 not taken.
|
29496 | trace_steps.end(); // because all steps are done |
| 1050 |
2/4✓ Branch 0 taken 29496 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29497 times.
✗ Branch 3 not taken.
|
29497 | Opt_trace_object(trace, "empty_result").add_alnum("cause", zero_result_cause); |
| 1051 | |||
| 1052 | 29497 | having_for_explain = having_cond; | |
| 1053 | 29497 | error = 0; | |
| 1054 | |||
| 1055 |
3/4✓ Branch 0 taken 29497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11463 times.
✓ Branch 3 taken 18034 times.
|
29497 | if (!qep_tab && best_ref) { |
| 1056 | /* | ||
| 1057 | After creation of JOIN_TABs in make_join_plan(), we have shortcut due to | ||
| 1058 | some zero_result_cause. For simplification, if we have JOIN_TABs we | ||
| 1059 | want QEP_TABs too. | ||
| 1060 | */ | ||
| 1061 |
2/4✓ Branch 0 taken 11463 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11463 times.
|
11463 | if (alloc_qep(tables)) return true; /* purecov: inspected */ |
| 1062 |
1/2✓ Branch 0 taken 11462 times.
✗ Branch 1 not taken.
|
11463 | unplug_join_tabs(); |
| 1063 | } | ||
| 1064 | |||
| 1065 |
1/2✓ Branch 0 taken 29497 times.
✗ Branch 1 not taken.
|
29496 | set_plan_state(ZERO_RESULT); |
| 1066 | 29497 | return false; | |
| 1067 | 9923746 | } | |
| 1068 | |||
| 1069 | 150 | void JOIN::change_to_access_path_without_in2exists() { | |
| 1070 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 150 times.
|
150 | if (m_root_access_path_no_in2exists != nullptr) { |
| 1071 | ✗ | m_root_access_path = m_root_access_path_no_in2exists; | |
| 1072 | } | ||
| 1073 | 150 | } | |
| 1074 | |||
| 1075 | 24416 | void JOIN::create_access_paths_for_zero_rows() { | |
| 1076 |
2/2✓ Branch 0 taken 8238 times.
✓ Branch 1 taken 16178 times.
|
24416 | if (send_row_on_empty_set()) { |
| 1077 | // Aggregate no rows into an aggregate row. | ||
| 1078 | 8238 | m_root_access_path = | |
| 1079 | 8238 | NewZeroRowsAggregatedAccessPath(thd, zero_result_cause); | |
| 1080 | 8238 | m_root_access_path = | |
| 1081 | 8238 | attach_access_paths_for_having_and_limit(m_root_access_path); | |
| 1082 | } else { | ||
| 1083 | // Send no row at all (so also no need to check HAVING or LIMIT). | ||
| 1084 | 16178 | m_root_access_path = NewZeroRowsAccessPath(thd, zero_result_cause); | |
| 1085 | } | ||
| 1086 | 24416 | m_root_access_path = | |
| 1087 | 24417 | attach_access_path_for_update_or_delete(m_root_access_path); | |
| 1088 | 24416 | } | |
| 1089 | |||
| 1090 | /** | ||
| 1091 | Push (parts of) the query execution down to the storage engines if they | ||
| 1092 | can provide faster execution of the query, or part of it. | ||
| 1093 | |||
| 1094 | The handler will inspect the QEP through the | ||
| 1095 | AQP (Abstract Query Plan) and extract from it whatever | ||
| 1096 | it might implement of pushed execution. | ||
| 1097 | |||
| 1098 | It is the responsibility of the handler to store | ||
| 1099 | any information it need for the later execution of | ||
| 1100 | pushed queries and conditions. | ||
| 1101 | |||
| 1102 | @retval false Success. | ||
| 1103 | @retval true Error, error code saved in member JOIN::error. | ||
| 1104 | */ | ||
| 1105 | 1900717 | bool JOIN::push_to_engines() { | |
| 1106 |
1/2✓ Branch 0 taken 1900728 times.
✗ Branch 1 not taken.
|
1900717 | DBUG_TRACE; |
| 1107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1900728 times.
|
1900728 | assert(m_root_access_path != nullptr); |
| 1108 | |||
| 1109 |
2/2✓ Branch 0 taken 3915155 times.
✓ Branch 1 taken 1900728 times.
|
5815883 | for (TABLE_LIST *tl = query_block->leaf_tables; tl; tl = tl->next_leaf) { |
| 1110 |
1/2✓ Branch 0 taken 3915155 times.
✗ Branch 1 not taken.
|
3915155 | const handlerton *hton = tl->table->file->hton_supporting_engine_pushdown(); |
| 1111 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3915155 times.
|
3915155 | if (hton != nullptr) { // Involved an engine supporting pushdown. |
| 1112 | ✗ | if (unlikely(hton->push_to_engine(thd, m_root_access_path, this))) { | |
| 1113 | ✗ | return true; | |
| 1114 | } | ||
| 1115 | ✗ | break; // Assume that at most a single handlerton per query support | |
| 1116 | // pushdown | ||
| 1117 | } | ||
| 1118 | } | ||
| 1119 | 1900728 | return false; | |
| 1120 | 1900728 | } | |
| 1121 | |||
| 1122 | /** | ||
| 1123 | Substitute all expressions in the WHERE condition and ORDER/GROUP lists | ||
| 1124 | that match generated columns (GC) expressions with GC fields, if any. | ||
| 1125 | |||
| 1126 | @details This function does 3 things: | ||
| 1127 | 1) Creates list of all GC fields that are a part of a key and the GC | ||
| 1128 | expression is a function. All query tables are scanned. If there's no | ||
| 1129 | such fields, function exits. | ||
| 1130 | 2) By means of Item::compile() WHERE clause is transformed. | ||
| 1131 | @see Item_func::gc_subst_transformer() for details. | ||
| 1132 | 3) If there's ORDER/GROUP BY clauses, this function tries to substitute | ||
| 1133 | expressions in these lists with GC too. It removes from the list of | ||
| 1134 | indexed GC all elements which index blocked by hints. This is done to | ||
| 1135 | reduce amount of further work. Next it goes through ORDER/GROUP BY list | ||
| 1136 | and matches the expression in it against GC expressions in indexed GC | ||
| 1137 | list. When a match is found, the expression is replaced with a new | ||
| 1138 | Item_field for the matched GC field. Also, this new field is added to | ||
| 1139 | the hidden part of all_fields list. | ||
| 1140 | |||
| 1141 | @param thd thread handle | ||
| 1142 | @param query_block the current select | ||
| 1143 | @param where_cond the WHERE condition, possibly NULL | ||
| 1144 | @param group_list the GROUP BY clause, possibly NULL | ||
| 1145 | @param order the ORDER BY clause, possibly NULL | ||
| 1146 | |||
| 1147 | @return true if the GROUP BY clause or the ORDER BY clause was | ||
| 1148 | changed, false otherwise | ||
| 1149 | */ | ||
| 1150 | |||
| 1151 | 1993185 | bool substitute_gc(THD *thd, Query_block *query_block, Item *where_cond, | |
| 1152 | ORDER *group_list, ORDER *order) { | ||
| 1153 | 1993185 | List<Field> indexed_gc; | |
| 1154 | 1993228 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 1155 |
1/2✓ Branch 0 taken 1993245 times.
✗ Branch 1 not taken.
|
1993228 | Opt_trace_object trace_wrapper(trace); |
| 1156 |
1/2✓ Branch 0 taken 1993270 times.
✗ Branch 1 not taken.
|
1993245 | Opt_trace_object subst_gc(trace, "substitute_generated_columns"); |
| 1157 | |||
| 1158 | // Collect all GCs that are a part of a key | ||
| 1159 |
2/2✓ Branch 0 taken 3993021 times.
✓ Branch 1 taken 1993380 times.
|
5986401 | for (TABLE_LIST *tl = query_block->leaf_tables; tl; tl = tl->next_leaf) { |
| 1160 |
2/2✓ Branch 0 taken 410588 times.
✓ Branch 1 taken 3582433 times.
|
3993021 | if (tl->table->s->keys == 0) continue; |
| 1161 |
2/2✓ Branch 0 taken 34601132 times.
✓ Branch 1 taken 3582543 times.
|
38183675 | for (uint i = 0; i < tl->table->s->fields; i++) { |
| 1162 | 34601132 | Field *fld = tl->table->field[i]; | |
| 1163 | 34601132 | if (fld->is_gcol() && | |
| 1164 |
2/2✓ Branch 0 taken 92307 times.
✓ Branch 1 taken 18542 times.
|
110849 | !(fld->part_of_key.is_clear_all() && |
| 1165 |
6/6✓ Branch 0 taken 110849 times.
✓ Branch 1 taken 34490340 times.
✓ Branch 2 taken 13258 times.
✓ Branch 3 taken 79049 times.
✓ Branch 4 taken 25244 times.
✓ Branch 5 taken 34575919 times.
|
34725270 | fld->part_of_prefixkey.is_clear_all()) && |
| 1166 |
3/4✓ Branch 0 taken 31774 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25244 times.
✓ Branch 3 taken 6530 times.
|
31800 | fld->gcol_info->expr_item->can_be_substituted_for_gc()) { |
| 1167 | // Don't check allowed keys here as conditions/group/order use | ||
| 1168 | // different keymaps for that. | ||
| 1169 |
1/2✓ Branch 0 taken 25323 times.
✗ Branch 1 not taken.
|
25244 | indexed_gc.push_back(fld); |
| 1170 | } | ||
| 1171 | } | ||
| 1172 | } | ||
| 1173 | // No GC in the tables used in the query | ||
| 1174 |
2/2✓ Branch 0 taken 1968781 times.
✓ Branch 1 taken 24599 times.
|
1993380 | if (indexed_gc.elements == 0) return false; |
| 1175 | |||
| 1176 |
2/2✓ Branch 0 taken 24323 times.
✓ Branch 1 taken 276 times.
|
24599 | if (where_cond) { |
| 1177 | // Item_func::compile will dereference this pointer, provide valid value. | ||
| 1178 | 24323 | uchar i, *dummy = &i; | |
| 1179 |
1/2✓ Branch 0 taken 24323 times.
✗ Branch 1 not taken.
|
24323 | if (where_cond->compile(&Item::gc_subst_analyzer, &dummy, |
| 1180 | &Item::gc_subst_transformer, | ||
| 1181 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24321 times.
|
24323 | pointer_cast<uchar *>(&indexed_gc)) == nullptr) |
| 1182 | 2 | return true; | |
| 1183 |
1/2✓ Branch 0 taken 24321 times.
✗ Branch 1 not taken.
|
24321 | subst_gc.add("resulting_condition", where_cond); |
| 1184 | } | ||
| 1185 | |||
| 1186 | // An error occur during substitution. Let caller handle it. | ||
| 1187 |
2/4✓ Branch 0 taken 24493 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24493 times.
|
24597 | if (thd->is_error()) return false; |
| 1188 | |||
| 1189 |
4/4✓ Branch 0 taken 24457 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 24150 times.
✓ Branch 3 taken 307 times.
|
24493 | if (!(group_list || order)) return false; |
| 1190 | // Filter out GCs that do not have index usable for GROUP/ORDER | ||
| 1191 | Field *gc; | ||
| 1192 |
1/2✓ Branch 0 taken 343 times.
✗ Branch 1 not taken.
|
343 | List_iterator<Field> li(indexed_gc); |
| 1193 | |||
| 1194 |
2/2✓ Branch 0 taken 489 times.
✓ Branch 1 taken 343 times.
|
832 | while ((gc = li++)) { |
| 1195 | 489 | Key_map tkm = gc->part_of_key; | |
| 1196 |
2/2✓ Branch 0 taken 109 times.
✓ Branch 1 taken 380 times.
|
869 | tkm.intersect(group_list ? gc->table->keys_in_use_for_group_by |
| 1197 | 380 | : gc->table->keys_in_use_for_order_by); | |
| 1198 |
3/4✓ Branch 0 taken 130 times.
✓ Branch 1 taken 359 times.
✓ Branch 2 taken 130 times.
✗ Branch 3 not taken.
|
489 | if (tkm.is_clear_all()) li.remove(); |
| 1199 | } | ||
| 1200 |
2/2✓ Branch 0 taken 119 times.
✓ Branch 1 taken 224 times.
|
343 | if (!indexed_gc.elements) return false; |
| 1201 | |||
| 1202 | // Index could be used for ORDER only if there is no GROUP | ||
| 1203 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 188 times.
|
224 | ORDER *list = group_list ? group_list : order; |
| 1204 | 224 | bool changed = false; | |
| 1205 |
2/2✓ Branch 0 taken 396 times.
✓ Branch 1 taken 224 times.
|
620 | for (ORDER *ord = list; ord; ord = ord->next) { |
| 1206 | 396 | li.rewind(); | |
| 1207 |
3/4✓ Branch 0 taken 396 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 383 times.
✓ Branch 3 taken 13 times.
|
396 | if (!(*ord->item)->can_be_substituted_for_gc()) continue; |
| 1208 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 12 times.
|
25 | while ((gc = li++)) { |
| 1209 | Item_field *const field = | ||
| 1210 |
2/4✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | get_gc_for_expr(*ord->item, gc, gc->result_type()); |
| 1211 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
|
13 | if (field != nullptr) { |
| 1212 | 1 | changed = true; | |
| 1213 | /* Add new field to field list. */ | ||
| 1214 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Item **new_field = query_block->add_hidden_item(field); |
| 1215 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | thd->change_item_tree(ord->item, *new_field); |
| 1216 | 1 | query_block->hidden_items_from_optimization++; | |
| 1217 | 1 | break; | |
| 1218 | } | ||
| 1219 | } | ||
| 1220 | } | ||
| 1221 | // An error occur during substitution. Let caller handle it. | ||
| 1222 |
2/4✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 224 times.
|
224 | if (thd->is_error()) return false; |
| 1223 | |||
| 1224 |
4/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 223 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 224 times.
|
224 | if (changed && trace->is_started()) { |
| 1225 | ✗ | String str; | |
| 1226 | ✗ | Query_block::print_order( | |
| 1227 | thd, &str, list, | ||
| 1228 | enum_query_type(QT_TO_SYSTEM_CHARSET | QT_SHOW_SELECT_NUMBER | | ||
| 1229 | QT_NO_DEFAULT_DB)); | ||
| 1230 | ✗ | subst_gc.add_utf8(group_list ? "resulting_GROUP_BY" : "resulting_ORDER_BY", | |
| 1231 | ✗ | str.ptr(), str.length()); | |
| 1232 | } | ||
| 1233 | 224 | return changed; | |
| 1234 | 1993276 | } | |
| 1235 | |||
| 1236 | /** | ||
| 1237 | Sets the plan's state of the JOIN. This is always the final step of | ||
| 1238 | optimization; starting from this call, we expose the plan to other | ||
| 1239 | connections (via EXPLAIN CONNECTION) so the plan has to be final. | ||
| 1240 | keyread_optim is set here. | ||
| 1241 | */ | ||
| 1242 | 19847142 | void JOIN::set_plan_state(enum_plan_state plan_state_arg) { | |
| 1243 | // A plan should not change to another plan: | ||
| 1244 |
3/4✓ Branch 0 taken 9923556 times.
✓ Branch 1 taken 9923586 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9923556 times.
|
19847142 | assert(plan_state_arg == NO_PLAN || plan_state == NO_PLAN); |
| 1245 |
4/4✓ Branch 0 taken 9923908 times.
✓ Branch 1 taken 9923234 times.
✓ Branch 2 taken 9923554 times.
✓ Branch 3 taken 354 times.
|
19847142 | if (plan_state == NO_PLAN && plan_state_arg != NO_PLAN) { |
| 1246 |
2/2✓ Branch 0 taken 1911981 times.
✓ Branch 1 taken 8011573 times.
|
9923554 | if (qep_tab != nullptr) { |
| 1247 | /* | ||
| 1248 | We want to cover primary tables, tmp tables. Note that | ||
| 1249 | make_tmp_tables_info() may have added a sort to the first non-const | ||
| 1250 | primary table, so it's important to do this assignment after | ||
| 1251 | make_tmp_tables_info(). | ||
| 1252 | */ | ||
| 1253 |
2/2✓ Branch 0 taken 6398096 times.
✓ Branch 1 taken 1911985 times.
|
8310081 | for (uint i = const_tables; i < tables; ++i) { |
| 1254 | 6398096 | qep_tab[i].set_condition_optim(); | |
| 1255 | 6398096 | qep_tab[i].set_keyread_optim(); | |
| 1256 | } | ||
| 1257 | } | ||
| 1258 | } | ||
| 1259 | |||
| 1260 |
2/2✓ Branch 0 taken 19800061 times.
✓ Branch 1 taken 47101 times.
|
19847146 | DEBUG_SYNC(thd, "before_set_plan"); |
| 1261 | |||
| 1262 | // If SQLCOM_END, no thread is explaining our statement anymore. | ||
| 1263 | 19847183 | const bool need_lock = thd->query_plan.get_command() != SQLCOM_END; | |
| 1264 | |||
| 1265 |
2/2✓ Branch 0 taken 10027413 times.
✓ Branch 1 taken 9819760 times.
|
19847173 | if (need_lock) thd->lock_query_plan(); |
| 1266 | 19847175 | plan_state = plan_state_arg; | |
| 1267 |
2/2✓ Branch 0 taken 10027415 times.
✓ Branch 1 taken 9819760 times.
|
19847175 | if (need_lock) thd->unlock_query_plan(); |
| 1268 | 19847182 | } | |
| 1269 | |||
| 1270 | 1911971 | bool JOIN::alloc_qep(uint n) { | |
| 1271 | static_assert(MAX_TABLES <= INT_MAX8, "plan_idx needs to be wide enough."); | ||
| 1272 | |||
| 1273 |
3/6✓ Branch 0 taken 1911974 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1911975 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1911982 times.
✗ Branch 5 not taken.
|
1911971 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 1274 | |||
| 1275 | 1911983 | qep_tab = new (thd->mem_root) | |
| 1276 |
4/6✓ Branch 0 taken 1911983 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1911984 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8410959 times.
✓ Branch 5 taken 1911971 times.
|
12234908 | QEP_TAB[n + 1]; // The last one holds only the final op_type. |
| 1277 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1911971 times.
|
1911971 | if (!qep_tab) return true; /* purecov: inspected */ |
| 1278 |
2/2✓ Branch 0 taken 6499068 times.
✓ Branch 1 taken 1911975 times.
|
8411039 | for (uint i = 0; i < n; ++i) qep_tab[i].init(best_ref[i]); |
| 1279 | 1911975 | return false; | |
| 1280 | } | ||
| 1281 | |||
| 1282 | 6499059 | void QEP_TAB::init(JOIN_TAB *jt) { | |
| 1283 | 6499059 | jt->share_qs(this); | |
| 1284 | 6499075 | set_table(table()); // to update table()->reginfo.qep_tab | |
| 1285 | 6499067 | table_ref = jt->table_ref; | |
| 1286 | 6499067 | } | |
| 1287 | |||
| 1288 | /// @returns semijoin strategy for this table. | ||
| 1289 | 87463 | uint QEP_TAB::get_sj_strategy() const { | |
| 1290 |
2/2✓ Branch 0 taken 86338 times.
✓ Branch 1 taken 1125 times.
|
87463 | if (first_sj_inner() == NO_PLAN_IDX) return SJ_OPT_NONE; |
| 1291 | 1125 | const uint s = join()->qep_tab[first_sj_inner()].position()->sj_strategy; | |
| 1292 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1125 times.
|
1125 | assert(s != SJ_OPT_NONE); |
| 1293 | 1125 | return s; | |
| 1294 | } | ||
| 1295 | |||
| 1296 | /** | ||
| 1297 | Return the index used for a table in a QEP | ||
| 1298 | |||
| 1299 | The various access methods have different places where the index/key | ||
| 1300 | number is stored, so this function is needed to return the correct value. | ||
| 1301 | |||
| 1302 | @returns index number, or MAX_KEY if not applicable. | ||
| 1303 | |||
| 1304 | JT_SYSTEM and JT_ALL does not use an index, and will always return MAX_KEY. | ||
| 1305 | |||
| 1306 | JT_INDEX_MERGE supports more than one index. Hence MAX_KEY is returned and | ||
| 1307 | a further inspection is needed. | ||
| 1308 | */ | ||
| 1309 | 10575 | uint QEP_TAB::effective_index() const { | |
| 1310 |
5/6✗ Branch 0 not taken.
✓ Branch 1 taken 615 times.
✓ Branch 2 taken 2504 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 336 times.
✓ Branch 5 taken 7096 times.
|
10575 | switch (type()) { |
| 1311 | ✗ | case JT_SYSTEM: | |
| 1312 | ✗ | assert(ref().key == -1); | |
| 1313 | ✗ | return MAX_KEY; | |
| 1314 | |||
| 1315 | 615 | case JT_CONST: | |
| 1316 | case JT_EQ_REF: | ||
| 1317 | case JT_REF_OR_NULL: | ||
| 1318 | case JT_REF: | ||
| 1319 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 615 times.
|
615 | assert(ref().key != -1); |
| 1320 | 615 | return uint(ref().key); | |
| 1321 | |||
| 1322 | 2504 | case JT_INDEX_SCAN: | |
| 1323 | case JT_FT: | ||
| 1324 | 2504 | return index(); | |
| 1325 | |||
| 1326 | 24 | case JT_INDEX_MERGE: | |
| 1327 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | assert(used_index(range_scan()) == MAX_KEY); |
| 1328 | 24 | return MAX_KEY; | |
| 1329 | |||
| 1330 | 336 | case JT_RANGE: | |
| 1331 | 336 | return used_index(range_scan()); | |
| 1332 | |||
| 1333 | 7096 | case JT_ALL: | |
| 1334 | default: | ||
| 1335 | // @todo Check why JT_UNKNOWN is a valid value here. | ||
| 1336 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7096 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7096 | assert(type() == JT_ALL || type() == JT_UNKNOWN); |
| 1337 | 7096 | return MAX_KEY; | |
| 1338 | } | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | 17282401 | uint JOIN_TAB::get_sj_strategy() const { | |
| 1342 |
2/2✓ Branch 0 taken 17215236 times.
✓ Branch 1 taken 67202 times.
|
17282401 | if (first_sj_inner() == NO_PLAN_IDX) return SJ_OPT_NONE; |
| 1343 |
3/6✓ Branch 0 taken 67202 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67202 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 67202 times.
✗ Branch 5 not taken.
|
67202 | ASSERT_BEST_REF_IN_JOIN_ORDER(join()); |
| 1344 | 67202 | JOIN_TAB *tab = join()->best_ref[first_sj_inner()]; | |
| 1345 | 67202 | uint s = tab->position()->sj_strategy; | |
| 1346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 67202 times.
|
67202 | assert(s != SJ_OPT_NONE); |
| 1347 | 67202 | return s; | |
| 1348 | } | ||
| 1349 | |||
| 1350 | 1900519 | int JOIN::replace_index_subquery() { | |
| 1351 |
1/2✓ Branch 0 taken 1900529 times.
✗ Branch 1 not taken.
|
1900519 | DBUG_TRACE; |
| 1352 |
3/6✓ Branch 0 taken 1900529 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1900529 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1900529 times.
✗ Branch 5 not taken.
|
1900529 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 1353 | |||
| 1354 | 1900529 | if (!group_list.empty() || | |
| 1355 |
2/2✓ Branch 0 taken 81230 times.
✓ Branch 1 taken 1807453 times.
|
1888682 | !(query_expression()->item && |
| 1356 |
3/4✓ Branch 0 taken 81230 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 876 times.
✓ Branch 3 taken 80354 times.
|
81230 | query_expression()->item->substype() == Item_subselect::IN_SUBS) || |
| 1357 |
10/10✓ Branch 0 taken 1888682 times.
✓ Branch 1 taken 11846 times.
✓ Branch 2 taken 790 times.
✓ Branch 3 taken 86 times.
✓ Branch 4 taken 647 times.
✓ Branch 5 taken 143 times.
✓ Branch 6 taken 19 times.
✓ Branch 7 taken 627 times.
✓ Branch 8 taken 1899900 times.
✓ Branch 9 taken 628 times.
|
3789211 | primary_tables != 1 || !where_cond || query_expression()->is_union()) |
| 1358 | 1899900 | return 0; | |
| 1359 | |||
| 1360 | // Guaranteed by remove_redundant_subquery_clauses(): | ||
| 1361 |
2/4✓ Branch 0 taken 627 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 627 times.
✗ Branch 3 not taken.
|
628 | assert(order.empty() && !select_distinct); |
| 1362 | |||
| 1363 | Item_in_subselect *const in_subs = | ||
| 1364 | 627 | static_cast<Item_in_subselect *>(query_expression()->item); | |
| 1365 | 627 | bool found_engine = false; | |
| 1366 | |||
| 1367 | 627 | JOIN_TAB *const first_join_tab = best_ref[0]; | |
| 1368 | |||
| 1369 |
2/2✓ Branch 0 taken 584 times.
✓ Branch 1 taken 43 times.
|
627 | if (in_subs->strategy == Subquery_strategy::SUBQ_MATERIALIZATION) { |
| 1370 | // We cannot have two engines at the same time | ||
| 1371 |
4/6✓ Branch 0 taken 27 times.
✓ Branch 1 taken 557 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 584 times.
✗ Branch 5 not taken.
|
611 | } else if (first_join_tab->table_ref->is_view_or_derived() && |
| 1372 | 27 | first_join_tab->table_ref->derived_query_expression() | |
| 1373 | 27 | ->is_recursive()) { | |
| 1374 | // The index subquery engine, which runs the derived table machinery | ||
| 1375 | // from the old executor, is not capable of materializing a WITH RECURSIVE | ||
| 1376 | // query from the iterator executor. Thus, be conservative here, so that the | ||
| 1377 | // case never happens. | ||
| 1378 |
2/2✓ Branch 0 taken 289 times.
✓ Branch 1 taken 295 times.
|
584 | } else if (having_cond == nullptr) { |
| 1379 | 289 | const join_type type = first_join_tab->type(); | |
| 1380 |
6/6✓ Branch 0 taken 222 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 155 times.
✓ Branch 4 taken 133 times.
✓ Branch 5 taken 156 times.
|
423 | if ((type == JT_EQ_REF || type == JT_REF) && |
| 1381 |
2/2✓ Branch 0 taken 133 times.
✓ Branch 1 taken 1 times.
|
134 | first_join_tab->ref().items[0]->item_name.ptr() == in_left_expr_name) { |
| 1382 | 133 | found_engine = true; | |
| 1383 | } | ||
| 1384 | 295 | } else if (first_join_tab->type() == JT_REF_OR_NULL && | |
| 1385 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | first_join_tab->ref().items[0]->item_name.ptr() == |
| 1386 |
4/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 281 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 281 times.
|
309 | in_left_expr_name && |
| 1387 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | having_cond->created_by_in2exists()) { |
| 1388 | 14 | found_engine = true; | |
| 1389 | } | ||
| 1390 | |||
| 1391 |
2/2✓ Branch 0 taken 480 times.
✓ Branch 1 taken 147 times.
|
627 | if (!found_engine) return 0; |
| 1392 | |||
| 1393 | /* Remove redundant predicates and cache constant expressions */ | ||
| 1394 |
2/4✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 147 times.
|
147 | if (finalize_table_conditions()) return -1; |
| 1395 | |||
| 1396 |
2/4✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 147 times.
|
147 | if (alloc_qep(tables)) return -1; /* purecov: inspected */ |
| 1397 |
1/2✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
|
147 | unplug_join_tabs(); |
| 1398 | |||
| 1399 | 147 | error = 0; | |
| 1400 | 147 | QEP_TAB *const first_qep_tab = &qep_tab[0]; | |
| 1401 | |||
| 1402 |
2/2✓ Branch 0 taken 135 times.
✓ Branch 1 taken 12 times.
|
147 | if (first_qep_tab->table()->covering_keys.is_set(first_qep_tab->ref().key)) { |
| 1403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
|
135 | assert(!first_qep_tab->table()->no_keyread); |
| 1404 |
1/2✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
|
135 | first_qep_tab->table()->set_keyread(true); |
| 1405 | } | ||
| 1406 | |||
| 1407 | subselect_indexsubquery_engine *engine = | ||
| 1408 | 147 | new (thd->mem_root) subselect_indexsubquery_engine( | |
| 1409 | 147 | first_qep_tab->table(), first_qep_tab->table_ref, | |
| 1410 | 147 | first_qep_tab->ref(), first_qep_tab->type(), | |
| 1411 | 147 | down_cast<Item_in_subselect *>(query_expression()->item), | |
| 1412 |
1/2✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
|
147 | first_qep_tab->condition(), having_cond); |
| 1413 | 147 | query_expression()->item->set_indexsubquery_engine(engine); | |
| 1414 | 147 | return 1; | |
| 1415 | 1900527 | } | |
| 1416 | |||
| 1417 | 1900520 | bool JOIN::optimize_distinct_group_order() { | |
| 1418 |
1/2✓ Branch 0 taken 1900539 times.
✗ Branch 1 not taken.
|
1900520 | DBUG_TRACE; |
| 1419 |
5/6✓ Branch 0 taken 1900538 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1900535 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1900535 times.
✗ Branch 5 not taken.
|
1900539 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 1420 | 1900536 | const bool windowing = m_windows.elements > 0; | |
| 1421 |
2/2✓ Branch 0 taken 1886312 times.
✓ Branch 1 taken 10229 times.
|
1896540 | const bool may_trace = select_distinct || !group_list.empty() || |
| 1422 |
6/6✓ Branch 0 taken 1896540 times.
✓ Branch 1 taken 3996 times.
✓ Branch 2 taken 1254629 times.
✓ Branch 3 taken 631684 times.
✓ Branch 4 taken 1253663 times.
✓ Branch 5 taken 966 times.
|
5050740 | !order.empty() || windowing || |
| 1423 |
2/2✓ Branch 0 taken 417389 times.
✓ Branch 1 taken 836274 times.
|
1253663 | tmp_table_param.sum_func_count; |
| 1424 | 1900538 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 1425 |
1/2✓ Branch 0 taken 1900535 times.
✗ Branch 1 not taken.
|
1900538 | Opt_trace_disable_I_S trace_disabled(trace, !may_trace); |
| 1426 |
1/2✓ Branch 0 taken 1900538 times.
✗ Branch 1 not taken.
|
1900535 | Opt_trace_object wrapper(trace); |
| 1427 |
1/2✓ Branch 0 taken 1900538 times.
✗ Branch 1 not taken.
|
1900538 | Opt_trace_object trace_opt(trace, "optimizing_distinct_group_by_order_by"); |
| 1428 | /* Optimize distinct away if possible */ | ||
| 1429 | { | ||
| 1430 | 1900538 | ORDER *org_order = order.order; | |
| 1431 | 1900522 | order = ORDER_with_src( | |
| 1432 |
1/2✓ Branch 0 taken 1900522 times.
✗ Branch 1 not taken.
|
1900538 | remove_const(order.order, where_cond, rollup_state == RollupState::NONE, |
| 1433 | &simple_order, false), | ||
| 1434 | order.src); | ||
| 1435 |
2/4✓ Branch 0 taken 1900534 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1900534 times.
|
1900525 | if (thd->is_error()) { |
| 1436 | ✗ | error = 1; | |
| 1437 | ✗ | DBUG_PRINT("error", ("Error from remove_const")); | |
| 1438 | ✗ | return true; | |
| 1439 | } | ||
| 1440 | |||
| 1441 | /* | ||
| 1442 | If we are using ORDER BY NULL or ORDER BY const_expression, | ||
| 1443 | return result in any order (even if we are using a GROUP BY) | ||
| 1444 | */ | ||
| 1445 |
6/6✓ Branch 0 taken 1268201 times.
✓ Branch 1 taken 632330 times.
✓ Branch 2 taken 3671 times.
✓ Branch 3 taken 1264530 times.
✓ Branch 4 taken 3671 times.
✓ Branch 5 taken 1896860 times.
|
1900534 | if (order.empty() && org_order) skip_sort_order = true; |
| 1446 | } | ||
| 1447 | /* | ||
| 1448 | Check if we can optimize away GROUP BY/DISTINCT. | ||
| 1449 | We can do that if there are no aggregate functions, the | ||
| 1450 | fields in DISTINCT clause (if present) and/or columns in GROUP BY | ||
| 1451 | (if present) contain direct references to all key parts of | ||
| 1452 | an unique index (in whatever order) and if the key parts of the | ||
| 1453 | unique index cannot contain NULLs. | ||
| 1454 | Note that the unique keys for DISTINCT and GROUP BY should not | ||
| 1455 | be the same (as long as they are unique). | ||
| 1456 | |||
| 1457 | The FROM clause must contain a single non-constant table. | ||
| 1458 | |||
| 1459 | @todo Apart from the LIS test, every condition depends only on facts | ||
| 1460 | which can be known in Query_block::prepare(), possibly this block should | ||
| 1461 | move there. | ||
| 1462 | */ | ||
| 1463 | |||
| 1464 | 1900531 | JOIN_TAB *const tab = best_ref[const_tables]; | |
| 1465 | |||
| 1466 |
4/4✓ Branch 0 taken 1352289 times.
✓ Branch 1 taken 8730 times.
✓ Branch 2 taken 2966 times.
✓ Branch 3 taken 1349323 times.
|
3261548 | if (plan_is_single_table() && (!group_list.empty() || select_distinct) && |
| 1467 |
8/8✓ Branch 0 taken 1361017 times.
✓ Branch 1 taken 539510 times.
✓ Branch 2 taken 4120 times.
✓ Branch 3 taken 7576 times.
✓ Branch 4 taken 306 times.
✓ Branch 5 taken 3814 times.
✓ Branch 6 taken 3960 times.
✓ Branch 7 taken 1896564 times.
|
3265968 | !tmp_table_param.sum_func_count && |
| 1468 | 4120 | (!tab->range_scan() || | |
| 1469 |
2/2✓ Branch 0 taken 146 times.
✓ Branch 1 taken 156 times.
|
307 | tab->range_scan()->type != AccessPath::GROUP_INDEX_SKIP_SCAN)) { |
| 1470 |
6/6✓ Branch 0 taken 1083 times.
✓ Branch 1 taken 2877 times.
✓ Branch 2 taken 991 times.
✓ Branch 3 taken 92 times.
✓ Branch 4 taken 157 times.
✓ Branch 5 taken 3803 times.
|
4951 | if (!group_list.empty() && rollup_state == RollupState::NONE && |
| 1471 |
2/2✓ Branch 0 taken 157 times.
✓ Branch 1 taken 834 times.
|
991 | list_contains_unique_index(tab, find_field_in_order_list, |
| 1472 |
1/2✓ Branch 0 taken 991 times.
✗ Branch 1 not taken.
|
991 | (void *)group_list.order)) { |
| 1473 | /* | ||
| 1474 | We have found that grouping can be removed since groups correspond to | ||
| 1475 | only one row anyway. | ||
| 1476 | */ | ||
| 1477 | 157 | group_list.clean(); | |
| 1478 | 157 | grouped = false; | |
| 1479 | } | ||
| 1480 |
4/4✓ Branch 0 taken 2938 times.
✓ Branch 1 taken 1022 times.
✓ Branch 2 taken 185 times.
✓ Branch 3 taken 3775 times.
|
6898 | if (select_distinct && |
| 1481 |
3/4✓ Branch 0 taken 2938 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 185 times.
✓ Branch 3 taken 2753 times.
|
2938 | list_contains_unique_index(tab, find_field_in_item_list, fields)) { |
| 1482 | 185 | select_distinct = false; | |
| 1483 |
1/2✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
|
185 | trace_opt.add("distinct_is_on_unique", true) |
| 1484 |
1/2✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
|
185 | .add("removed_distinct", true); |
| 1485 | } | ||
| 1486 | } | ||
| 1487 |
4/4✓ Branch 0 taken 1472861 times.
✓ Branch 1 taken 417400 times.
✓ Branch 2 taken 1471794 times.
✓ Branch 3 taken 1067 times.
|
3790785 | if (!(!group_list.empty() || tmp_table_param.sum_func_count || windowing) && |
| 1488 |
8/8✓ Branch 0 taken 1890261 times.
✓ Branch 1 taken 10264 times.
✓ Branch 2 taken 3639 times.
✓ Branch 3 taken 1468155 times.
✓ Branch 4 taken 2803 times.
✓ Branch 5 taken 836 times.
✓ Branch 6 taken 2803 times.
✓ Branch 7 taken 1897722 times.
|
3793589 | select_distinct && plan_is_single_table() && |
| 1489 |
1/2✓ Branch 0 taken 2803 times.
✗ Branch 1 not taken.
|
2803 | rollup_state == RollupState::NONE) { |
| 1490 | 2803 | int order_idx = -1, group_idx = -1; | |
| 1491 | /* | ||
| 1492 | We are only using one table. In this case we change DISTINCT to a | ||
| 1493 | GROUP BY query if: | ||
| 1494 | - The GROUP BY can be done through indexes (no sort) and the ORDER | ||
| 1495 | BY only uses selected fields. | ||
| 1496 | (In this case we can later optimize away GROUP BY and ORDER BY) | ||
| 1497 | - We are scanning the whole table without LIMIT | ||
| 1498 | This can happen if: | ||
| 1499 | - We are using CALC_FOUND_ROWS | ||
| 1500 | - We are using an ORDER BY that can't be optimized away. | ||
| 1501 | - Selected expressions are not set functions (those cannot be put | ||
| 1502 | into GROUP BY). | ||
| 1503 | |||
| 1504 | We don't want to use this optimization when we are using LIMIT | ||
| 1505 | because in this case we can just create a temporary table that | ||
| 1506 | holds LIMIT rows and stop when this table is full. | ||
| 1507 | */ | ||
| 1508 |
2/2✓ Branch 0 taken 264 times.
✓ Branch 1 taken 2539 times.
|
2803 | if (!order.empty()) { |
| 1509 | 528 | skip_sort_order = test_if_skip_sort_order( | |
| 1510 | 264 | tab, order, m_select_limit, | |
| 1511 | true, // no_changes | ||
| 1512 |
1/2✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
|
264 | &tab->table()->keys_in_use_for_order_by, &order_idx); |
| 1513 |
1/2✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
|
264 | count_field_types(query_block, &tmp_table_param, *fields, false, false); |
| 1514 | } | ||
| 1515 | ORDER *o; | ||
| 1516 | bool all_order_fields_used; | ||
| 1517 | /* | ||
| 1518 | There is possibility where the REF_SLICE_ACTIVE points to | ||
| 1519 | freed-up Items like in case of non-first row of a UPDATE | ||
| 1520 | trigger. Re-load the Items before using the slice. | ||
| 1521 | */ | ||
| 1522 |
1/2✓ Branch 0 taken 2803 times.
✗ Branch 1 not taken.
|
2803 | refresh_base_slice(); |
| 1523 |
2/2✓ Branch 0 taken 2782 times.
✓ Branch 1 taken 21 times.
|
2803 | if ((o = create_order_from_distinct( |
| 1524 |
1/2✓ Branch 0 taken 2803 times.
✗ Branch 1 not taken.
|
2803 | thd, ref_items[REF_SLICE_ACTIVE], order.order, fields, |
| 1525 | /*skip_aggregates=*/true, | ||
| 1526 | /*convert_bit_fields_to_long=*/true, &all_order_fields_used))) { | ||
| 1527 | 2782 | group_list = ORDER_with_src(o, ESC_DISTINCT); | |
| 1528 | const bool skip_group = | ||
| 1529 |
2/2✓ Branch 0 taken 61 times.
✓ Branch 1 taken 2721 times.
|
2843 | skip_sort_order && |
| 1530 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 10 times.
|
61 | test_if_skip_sort_order(tab, group_list, m_select_limit, |
| 1531 | true, // no_changes | ||
| 1532 |
1/2✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
|
61 | &tab->table()->keys_in_use_for_group_by, |
| 1533 | 2782 | &group_idx); | |
| 1534 |
1/2✓ Branch 0 taken 2782 times.
✗ Branch 1 not taken.
|
2782 | count_field_types(query_block, &tmp_table_param, *fields, false, false); |
| 1535 | // ORDER BY and GROUP BY are using different indexes, can't skip sorting | ||
| 1536 |
6/6✓ Branch 0 taken 51 times.
✓ Branch 1 taken 2731 times.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 43 times.
|
2782 | if (group_idx >= 0 && order_idx >= 0 && group_idx != order_idx) |
| 1537 | 2 | skip_sort_order = false; | |
| 1538 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 49 times.
|
51 | if ((skip_group && all_order_fields_used) || |
| 1539 |
6/6✓ Branch 0 taken 51 times.
✓ Branch 1 taken 2731 times.
✓ Branch 2 taken 81 times.
✓ Branch 3 taken 2652 times.
✓ Branch 4 taken 2730 times.
✓ Branch 5 taken 52 times.
|
2914 | m_select_limit == HA_POS_ERROR || |
| 1540 |
4/4✓ Branch 0 taken 33 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 4 times.
|
81 | (!order.empty() && !skip_sort_order)) { |
| 1541 | /* Change DISTINCT to GROUP BY */ | ||
| 1542 | 2730 | select_distinct = false; | |
| 1543 | /* | ||
| 1544 | group_list was created with ORDER BY clause as prefix and | ||
| 1545 | replaces it. So it must respect ordering. If there is no | ||
| 1546 | ORDER BY, GROUP BY need not have to provide order. | ||
| 1547 | */ | ||
| 1548 |
2/2✓ Branch 0 taken 2472 times.
✓ Branch 1 taken 258 times.
|
2730 | if (order.empty()) { |
| 1549 |
2/2✓ Branch 0 taken 3610 times.
✓ Branch 1 taken 2472 times.
|
6082 | for (ORDER *group = group_list.order; group; group = group->next) |
| 1550 | 3610 | group->direction = ORDER_NOT_RELEVANT; | |
| 1551 | } | ||
| 1552 |
8/8✓ Branch 0 taken 2689 times.
✓ Branch 1 taken 41 times.
✓ Branch 2 taken 55 times.
✓ Branch 3 taken 2634 times.
✓ Branch 4 taken 43 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 43 times.
✓ Branch 7 taken 2687 times.
|
2730 | if (all_order_fields_used && skip_sort_order && !order.empty()) { |
| 1553 | /* | ||
| 1554 | Force MySQL to read the table in sorted order to get result in | ||
| 1555 | ORDER BY order. | ||
| 1556 | */ | ||
| 1557 | 43 | tmp_table_param.allow_group_via_temp_table = false; | |
| 1558 | } | ||
| 1559 | 2730 | grouped = true; // For end_write_group | |
| 1560 |
1/2✓ Branch 0 taken 2730 times.
✗ Branch 1 not taken.
|
2730 | trace_opt.add("changed_distinct_to_group_by", true); |
| 1561 | } else | ||
| 1562 | 52 | group_list.clean(); | |
| 1563 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | } else if (thd->is_fatal_error()) // End of memory |
| 1564 | ✗ | return true; | |
| 1565 | } | ||
| 1566 | 1900525 | simple_group = false; | |
| 1567 | |||
| 1568 | 1900525 | ORDER *old_group_list = group_list.order; | |
| 1569 | 1900536 | group_list = ORDER_with_src( | |
| 1570 | remove_const(group_list.order, where_cond, | ||
| 1571 |
1/2✓ Branch 0 taken 1900536 times.
✗ Branch 1 not taken.
|
1900525 | rollup_state == RollupState::NONE, &simple_group, true), |
| 1572 | group_list.src); | ||
| 1573 | |||
| 1574 |
2/4✓ Branch 0 taken 1900537 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1900537 times.
|
1900539 | if (thd->is_error()) { |
| 1575 | ✗ | error = 1; | |
| 1576 | ✗ | DBUG_PRINT("error", ("Error from remove_const")); | |
| 1577 | ✗ | return true; | |
| 1578 | } | ||
| 1579 |
6/6✓ Branch 0 taken 12996 times.
✓ Branch 1 taken 1887541 times.
✓ Branch 2 taken 1150 times.
✓ Branch 3 taken 11846 times.
✓ Branch 4 taken 1150 times.
✓ Branch 5 taken 1899387 times.
|
1900537 | if (old_group_list && group_list.empty()) select_distinct = false; |
| 1580 | |||
| 1581 |
6/6✓ Branch 0 taken 1888689 times.
✓ Branch 1 taken 11847 times.
✓ Branch 2 taken 1150 times.
✓ Branch 3 taken 1887539 times.
✓ Branch 4 taken 1150 times.
✓ Branch 5 taken 1899386 times.
|
1900537 | if (group_list.empty() && grouped) { |
| 1582 | 1150 | order.clean(); // The output has only one row | |
| 1583 | 1150 | simple_order = true; | |
| 1584 | 1150 | select_distinct = false; // No need in distinct for 1 row | |
| 1585 | 1150 | group_optimized_away = true; | |
| 1586 | } | ||
| 1587 | |||
| 1588 |
1/2✓ Branch 0 taken 1900524 times.
✗ Branch 1 not taken.
|
1900536 | calc_group_buffer(this, group_list.order); |
| 1589 | 1900524 | send_group_parts = tmp_table_param.group_parts; /* Save org parts */ | |
| 1590 | |||
| 1591 | /* | ||
| 1592 | If ORDER BY is a prefix of GROUP BY and if windowing or ROLLUP | ||
| 1593 | doesn't change this order, ORDER BY can be removed and we can | ||
| 1594 | enforce GROUP BY to provide order. | ||
| 1595 | Also true if the result is one row. | ||
| 1596 | */ | ||
| 1597 |
3/4✓ Branch 0 taken 1900530 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1270204 times.
✓ Branch 3 taken 793 times.
|
3171521 | if ((test_if_subpart(group_list.order, order.order) && !m_windows_sort && |
| 1598 |
8/8✓ Branch 0 taken 1270997 times.
✓ Branch 1 taken 629533 times.
✓ Branch 2 taken 287 times.
✓ Branch 3 taken 1269917 times.
✓ Branch 4 taken 629699 times.
✓ Branch 5 taken 919 times.
✓ Branch 6 taken 1269918 times.
✓ Branch 7 taken 630617 times.
|
4431051 | query_block->olap != ROLLUP_TYPE) || |
| 1599 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 629698 times.
|
1260312 | (group_list.empty() && tmp_table_param.sum_func_count)) { |
| 1600 |
2/2✓ Branch 0 taken 2746 times.
✓ Branch 1 taken 1267172 times.
|
1269918 | if (!order.empty()) { |
| 1601 | 2746 | order.clean(); | |
| 1602 |
1/2✓ Branch 0 taken 2746 times.
✗ Branch 1 not taken.
|
2746 | trace_opt.add("removed_order_by", true); |
| 1603 | } | ||
| 1604 |
3/4✓ Branch 0 taken 1269904 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 400 times.
✓ Branch 3 taken 1269504 times.
|
1269918 | if (is_indexed_agg_distinct(this, nullptr)) streaming_aggregation = false; |
| 1605 | } | ||
| 1606 | |||
| 1607 | 1900521 | return false; | |
| 1608 | 1900521 | } | |
| 1609 | |||
| 1610 | 1813728 | void JOIN::test_skip_sort() { | |
| 1611 |
1/2✓ Branch 0 taken 1813733 times.
✗ Branch 1 not taken.
|
1813728 | DBUG_TRACE; |
| 1612 |
4/6✓ Branch 0 taken 1813734 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1813729 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 1813732 times.
✗ Branch 5 not taken.
|
1813733 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 1613 | 1813731 | JOIN_TAB *const tab = best_ref[const_tables]; | |
| 1614 | |||
| 1615 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1813731 times.
|
1813731 | assert(m_ordered_index_usage == ORDERED_INDEX_VOID); |
| 1616 | |||
| 1617 |
2/2✓ Branch 0 taken 11842 times.
✓ Branch 1 taken 1801890 times.
|
1813731 | if (!group_list.empty()) // GROUP BY honoured first |
| 1618 | // (DISTINCT was rewritten to GROUP BY if skippable) | ||
| 1619 | { | ||
| 1620 | /* | ||
| 1621 | When there is SQL_BIG_RESULT or a JSON aggregation function, | ||
| 1622 | do not sort using index for GROUP BY, and thus force sorting on disk | ||
| 1623 | unless a group min-max optimization is going to be used as it is applied | ||
| 1624 | now only for one table queries with covering indexes. | ||
| 1625 | */ | ||
| 1626 |
8/8✓ Branch 0 taken 11786 times.
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 11782 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 58 times.
✓ Branch 6 taken 11784 times.
✓ Branch 7 taken 58 times.
|
11904 | if (!(query_block->active_options() & SELECT_BIG_RESULT || with_json_agg) || |
| 1627 | 60 | (tab->range_scan() && | |
| 1628 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | tab->range_scan()->type == AccessPath::GROUP_INDEX_SKIP_SCAN)) { |
| 1629 |
2/2✓ Branch 0 taken 10232 times.
✓ Branch 1 taken 1552 times.
|
11784 | if (simple_group && // GROUP BY is possibly skippable |
| 1630 |
2/2✓ Branch 0 taken 10111 times.
✓ Branch 1 taken 121 times.
|
10232 | !select_distinct) // .. if not preceded by a DISTINCT |
| 1631 | { | ||
| 1632 | /* | ||
| 1633 | Calculate a possible 'limit' of table rows for 'GROUP BY': | ||
| 1634 | A specified 'LIMIT' is relative to the final resultset. | ||
| 1635 | 'need_tmp' implies that there will be more postprocessing | ||
| 1636 | so the specified 'limit' should not be enforced yet. | ||
| 1637 | */ | ||
| 1638 | 10111 | const ha_rows limit = | |
| 1639 |
2/2✓ Branch 0 taken 386 times.
✓ Branch 1 taken 9725 times.
|
10111 | (need_tmp_before_win ? HA_POS_ERROR : m_select_limit); |
| 1640 | int dummy; | ||
| 1641 | |||
| 1642 |
2/2✓ Branch 0 taken 1478 times.
✓ Branch 1 taken 8633 times.
|
10111 | if (test_if_skip_sort_order(tab, group_list, limit, false, |
| 1643 |
1/2✓ Branch 0 taken 10111 times.
✗ Branch 1 not taken.
|
10111 | &tab->table()->keys_in_use_for_group_by, |
| 1644 | &dummy)) { | ||
| 1645 | 1478 | m_ordered_index_usage = ORDERED_INDEX_GROUP_BY; | |
| 1646 | } | ||
| 1647 | } | ||
| 1648 | |||
| 1649 | /* | ||
| 1650 | If we are going to use semi-join LooseScan, it will depend | ||
| 1651 | on the selected index scan to be used. If index is not used | ||
| 1652 | for the GROUP BY, we risk that sorting is put on the LooseScan | ||
| 1653 | table. In order to avoid this, force use of temporary table. | ||
| 1654 | TODO: Explain the allow_group_via_temp_table part of the test below. | ||
| 1655 | */ | ||
| 1656 |
4/4✓ Branch 0 taken 10306 times.
✓ Branch 1 taken 1478 times.
✓ Branch 2 taken 9484 times.
✓ Branch 3 taken 2300 times.
|
22090 | if ((m_ordered_index_usage != ORDERED_INDEX_GROUP_BY) && |
| 1657 |
2/2✓ Branch 0 taken 822 times.
✓ Branch 1 taken 9484 times.
|
10306 | (tmp_table_param.allow_group_via_temp_table || |
| 1658 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 822 times.
|
822 | (tab->emb_sj_nest && |
| 1659 | ✗ | tab->position()->sj_strategy == SJ_OPT_LOOSE_SCAN))) { | |
| 1660 | 9484 | need_tmp_before_win = true; | |
| 1661 | 9484 | simple_order = simple_group = false; // Force tmp table without sort | |
| 1662 | } | ||
| 1663 | } | ||
| 1664 | 1801890 | } else if (!order.empty() && // ORDER BY wo/ preceding GROUP BY | |
| 1665 |
2/2✓ Branch 0 taken 271598 times.
✓ Branch 1 taken 357383 times.
|
628981 | (simple_order || |
| 1666 |
5/6✓ Branch 0 taken 628981 times.
✓ Branch 1 taken 1172896 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 271598 times.
✓ Branch 4 taken 357322 times.
✓ Branch 5 taken 1444555 times.
|
2430858 | skip_sort_order) && // which is possibly skippable, |
| 1667 |
2/2✓ Branch 0 taken 357322 times.
✓ Branch 1 taken 61 times.
|
357383 | !m_windows_sort) // and WFs will not shuffle rows |
| 1668 | { | ||
| 1669 | int dummy; | ||
| 1670 |
2/2✓ Branch 0 taken 21102 times.
✓ Branch 1 taken 336220 times.
|
357322 | if ((skip_sort_order = test_if_skip_sort_order( |
| 1671 | 357322 | tab, order, m_select_limit, false, | |
| 1672 |
1/2✓ Branch 0 taken 357322 times.
✗ Branch 1 not taken.
|
357322 | &tab->table()->keys_in_use_for_order_by, &dummy))) { |
| 1673 | 21102 | m_ordered_index_usage = ORDERED_INDEX_ORDER_BY; | |
| 1674 | } | ||
| 1675 | } | ||
| 1676 | 1813719 | } | |
| 1677 | |||
| 1678 | /** | ||
| 1679 | Test if ORDER BY is a single MATCH function(ORDER BY MATCH) | ||
| 1680 | and sort order is descending. | ||
| 1681 | |||
| 1682 | @param order pointer to ORDER struct. | ||
| 1683 | |||
| 1684 | @retval | ||
| 1685 | Pointer to MATCH function if order is 'ORDER BY MATCH() DESC' | ||
| 1686 | @retval | ||
| 1687 | NULL otherwise | ||
| 1688 | */ | ||
| 1689 | |||
| 1690 | 357828 | static Item_func_match *test_if_ft_index_order(ORDER *order) { | |
| 1691 |
7/8✓ Branch 0 taken 357828 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 270190 times.
✓ Branch 3 taken 87638 times.
✓ Branch 4 taken 4269 times.
✓ Branch 5 taken 265921 times.
✓ Branch 6 taken 72 times.
✓ Branch 7 taken 357756 times.
|
362097 | if (order && order->next == nullptr && order->direction == ORDER_DESC && |
| 1692 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 4197 times.
|
4269 | is_function_of_type(*order->item, Item_func::FT_FUNC)) |
| 1693 | 72 | return down_cast<Item_func_match *>(*order->item)->get_master(); | |
| 1694 | |||
| 1695 | 357756 | return nullptr; | |
| 1696 | } | ||
| 1697 | |||
| 1698 | /** | ||
| 1699 | Test if this is a prefix index. | ||
| 1700 | |||
| 1701 | @param table table | ||
| 1702 | @param idx index to check | ||
| 1703 | |||
| 1704 | @return TRUE if this is a prefix index | ||
| 1705 | */ | ||
| 1706 | 63 | bool is_prefix_index(TABLE *table, uint idx) { | |
| 1707 |
2/4✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 63 times.
|
63 | if (!table || !table->key_info) { |
| 1708 | ✗ | return false; | |
| 1709 | } | ||
| 1710 | |||
| 1711 | 63 | KEY *key_info = table->key_info; | |
| 1712 | 63 | uint key_parts = key_info[idx].user_defined_key_parts; | |
| 1713 | 63 | KEY_PART_INFO *key_part = key_info[idx].key_part; | |
| 1714 | |||
| 1715 |
2/2✓ Branch 0 taken 128 times.
✓ Branch 1 taken 61 times.
|
189 | for (uint i = 0; i < key_parts; i++, key_part++) { |
| 1716 | 384 | if (key_part->field && | |
| 1717 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 126 times.
|
128 | !(table->field[key_part->fieldnr - 1] |
| 1718 |
3/4✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 126 times.
|
256 | ->part_of_prefixkey.is_clear_all()) && |
| 1719 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | !(key_info->flags & (HA_FULLTEXT | HA_SPATIAL))) { |
| 1720 | 2 | return true; | |
| 1721 | } | ||
| 1722 | } | ||
| 1723 | 61 | return false; | |
| 1724 | } | ||
| 1725 | |||
| 1726 | /** | ||
| 1727 | Test if one can use the key to resolve ordering. | ||
| 1728 | |||
| 1729 | @param order_src Sort order | ||
| 1730 | @param table Table to sort | ||
| 1731 | @param idx Index to check | ||
| 1732 | @param[out] used_key_parts NULL by default, otherwise return value for | ||
| 1733 | used key parts. | ||
| 1734 | @param[out] skip_quick Whether found index can be used for backward range | ||
| 1735 | scans | ||
| 1736 | |||
| 1737 | @note | ||
| 1738 | used_key_parts is set to correct key parts used if return value != 0 | ||
| 1739 | (On other cases, used_key_part may be changed) | ||
| 1740 | Note that the value may actually be greater than the number of index | ||
| 1741 | key parts. This can happen for storage engines that have the primary | ||
| 1742 | key parts as a suffix for every secondary key. | ||
| 1743 | |||
| 1744 | @retval | ||
| 1745 | 1 key is ok. | ||
| 1746 | @retval | ||
| 1747 | 0 Key can't be used | ||
| 1748 | @retval | ||
| 1749 | -1 Reverse key can be used | ||
| 1750 | */ | ||
| 1751 | |||
| 1752 | 70260 | int test_if_order_by_key(ORDER_with_src *order_src, TABLE *table, uint idx, | |
| 1753 | uint *used_key_parts, bool *skip_quick) { | ||
| 1754 |
1/2✓ Branch 0 taken 70260 times.
✗ Branch 1 not taken.
|
70260 | DBUG_TRACE; |
| 1755 | KEY_PART_INFO *key_part, *key_part_end; | ||
| 1756 | 70260 | key_part = table->key_info[idx].key_part; | |
| 1757 | 70260 | key_part_end = key_part + table->key_info[idx].user_defined_key_parts; | |
| 1758 | 70260 | key_part_map const_key_parts = table->const_key_parts[idx]; | |
| 1759 | 70260 | int reverse = 0; | |
| 1760 | uint key_parts; | ||
| 1761 | 70260 | bool on_pk_suffix = false; | |
| 1762 | // Whether [extended] key has key parts with mixed ASC/DESC order | ||
| 1763 | 70260 | bool mixed_order = false; | |
| 1764 | // Order direction of the first key part | ||
| 1765 | 70260 | bool reverse_sorted = (bool)(key_part->key_part_flag & HA_REVERSE_SORT); | |
| 1766 | 70260 | ORDER *order = order_src->order; | |
| 1767 | 70260 | *skip_quick = false; | |
| 1768 | |||
| 1769 |
2/2✓ Branch 0 taken 79959 times.
✓ Branch 1 taken 58917 times.
|
138876 | for (; order; order = order->next, const_key_parts >>= 1) { |
| 1770 | /* | ||
| 1771 | Since only fields can be indexed, ORDER BY <something> that is | ||
| 1772 | not a field cannot be resolved by using an index. | ||
| 1773 | */ | ||
| 1774 |
1/2✓ Branch 0 taken 79959 times.
✗ Branch 1 not taken.
|
79959 | Item *real_itm = (*order->item)->real_item(); |
| 1775 |
3/4✓ Branch 0 taken 79959 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 79933 times.
|
79959 | if (real_itm->type() != Item::FIELD_ITEM) return 0; |
| 1776 | |||
| 1777 | 79933 | const Field *field = down_cast<const Item_field *>(real_itm)->field; | |
| 1778 | |||
| 1779 | /* | ||
| 1780 | Skip key parts that are constants in the WHERE clause. | ||
| 1781 | These are already skipped in the ORDER BY by check_field_is_const() | ||
| 1782 | */ | ||
| 1783 |
4/4✓ Branch 0 taken 6713 times.
✓ Branch 1 taken 79921 times.
✓ Branch 2 taken 6701 times.
✓ Branch 3 taken 12 times.
|
86634 | for (; const_key_parts & 1 && key_part < key_part_end; |
| 1784 | 6701 | const_key_parts >>= 1) | |
| 1785 | 6701 | key_part++; | |
| 1786 | |||
| 1787 | /* Avoid usage of prefix index for sorting a partition table */ | ||
| 1788 |
4/4✓ Branch 0 taken 68 times.
✓ Branch 1 taken 1584 times.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 5 times.
|
1652 | if (table->part_info && key_part != table->key_info[idx].key_part && |
| 1789 |
7/8✓ Branch 0 taken 1652 times.
✓ Branch 1 taken 78281 times.
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 61 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 79931 times.
|
81585 | key_part != key_part_end && is_prefix_index(table, idx)) |
| 1790 | 2 | return 0; | |
| 1791 | |||
| 1792 |
2/2✓ Branch 0 taken 624 times.
✓ Branch 1 taken 79307 times.
|
79931 | if (key_part == key_part_end) { |
| 1793 | /* | ||
| 1794 | We are at the end of the key. Check if the engine has the primary | ||
| 1795 | key as a suffix to the secondary keys. If it has continue to check | ||
| 1796 | the primary key as a suffix. | ||
| 1797 | */ | ||
| 1798 | 1872 | if (!on_pk_suffix && | |
| 1799 |
2/2✓ Branch 0 taken 605 times.
✓ Branch 1 taken 19 times.
|
624 | (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && |
| 1800 |
7/8✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 387 times.
✓ Branch 3 taken 218 times.
✓ Branch 4 taken 332 times.
✓ Branch 5 taken 55 times.
✓ Branch 6 taken 332 times.
✓ Branch 7 taken 292 times.
|
1248 | table->s->primary_key != MAX_KEY && table->s->primary_key != idx) { |
| 1801 | 332 | on_pk_suffix = true; | |
| 1802 | 332 | key_part = table->key_info[table->s->primary_key].key_part; | |
| 1803 | 332 | key_part_end = | |
| 1804 | 332 | key_part + | |
| 1805 | 332 | table->key_info[table->s->primary_key].user_defined_key_parts; | |
| 1806 | 332 | const_key_parts = table->const_key_parts[table->s->primary_key]; | |
| 1807 | |||
| 1808 |
3/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 332 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
341 | for (; const_key_parts & 1 && key_part < key_part_end; |
| 1809 | 9 | const_key_parts >>= 1) | |
| 1810 | 9 | key_part++; | |
| 1811 | /* | ||
| 1812 | The primary and secondary key parts were all const (i.e. there's | ||
| 1813 | one row). The sorting doesn't matter. | ||
| 1814 | */ | ||
| 1815 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 332 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
332 | if (key_part == key_part_end && reverse == 0) { |
| 1816 | ✗ | key_parts = 0; | |
| 1817 | ✗ | reverse = 1; | |
| 1818 | ✗ | goto ok; | |
| 1819 | } | ||
| 1820 | } else | ||
| 1821 | 292 | return 0; | |
| 1822 | } | ||
| 1823 | |||
| 1824 |
6/6✓ Branch 0 taken 72905 times.
✓ Branch 1 taken 6734 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 72883 times.
✓ Branch 4 taken 6756 times.
✓ Branch 5 taken 72883 times.
|
79639 | if (key_part->field != field || !field->part_of_sortkey.is_set(idx)) |
| 1825 | 6756 | return 0; | |
| 1826 |
2/2✓ Branch 0 taken 70754 times.
✓ Branch 1 taken 2129 times.
|
72883 | if (order->direction != ORDER_NOT_RELEVANT) { |
| 1827 | 70754 | const enum_order keypart_order = | |
| 1828 |
2/2✓ Branch 0 taken 176 times.
✓ Branch 1 taken 70578 times.
|
70754 | (key_part->key_part_flag & HA_REVERSE_SORT) ? ORDER_DESC : ORDER_ASC; |
| 1829 | /* set flag to 1 if we can use read-next on key, else to -1 */ | ||
| 1830 |
2/2✓ Branch 0 taken 57306 times.
✓ Branch 1 taken 13448 times.
|
70754 | int cur_scan_dir = (order->direction == keypart_order) ? 1 : -1; |
| 1831 |
4/4✓ Branch 0 taken 9033 times.
✓ Branch 1 taken 61721 times.
✓ Branch 2 taken 4267 times.
✓ Branch 3 taken 4766 times.
|
70754 | if (reverse && cur_scan_dir != reverse) return 0; |
| 1832 | 66487 | reverse = cur_scan_dir; // Remember if reverse | |
| 1833 | } | ||
| 1834 | 68616 | mixed_order |= | |
| 1835 | 68616 | (reverse_sorted != (bool)((key_part)->key_part_flag & HA_REVERSE_SORT)); | |
| 1836 | |||
| 1837 | 68616 | key_part++; | |
| 1838 | } | ||
| 1839 | /* | ||
| 1840 | The index picked here might be used for range scans with multiple ranges. | ||
| 1841 | This will require tricky reordering in case of ranges would have to be | ||
| 1842 | scanned backward and index consists of mixed ASC/DESC key parts. Due to that | ||
| 1843 | backward scans on such indexes are disabled. | ||
| 1844 | */ | ||
| 1845 |
4/4✓ Branch 0 taken 165 times.
✓ Branch 1 taken 58752 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 130 times.
|
58917 | if (mixed_order && reverse < 0) *skip_quick = true; |
| 1846 | |||
| 1847 |
2/2✓ Branch 0 taken 1759 times.
✓ Branch 1 taken 57158 times.
|
58917 | if (!reverse) { |
| 1848 | /* | ||
| 1849 | We get here when the key is suitable and we don't care about it's | ||
| 1850 | order, i.e. GROUP BY/DISTINCT. Use forward scan. | ||
| 1851 | */ | ||
| 1852 | 1759 | reverse = 1; | |
| 1853 | } | ||
| 1854 |
2/2✓ Branch 0 taken 182 times.
✓ Branch 1 taken 58735 times.
|
58917 | if (on_pk_suffix) { |
| 1855 | 182 | uint used_key_parts_secondary = table->key_info[idx].user_defined_key_parts; | |
| 1856 | 182 | uint used_key_parts_pk = | |
| 1857 | 182 | (uint)(key_part - table->key_info[table->s->primary_key].key_part); | |
| 1858 | 182 | key_parts = used_key_parts_pk + used_key_parts_secondary; | |
| 1859 | |||
| 1860 |
3/4✓ Branch 0 taken 102 times.
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 182 times.
|
284 | if (reverse == -1 && |
| 1861 |
2/4✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
|
102 | (!(table->file->index_flags(idx, used_key_parts_secondary - 1, true) & |
| 1862 | 102 | HA_READ_PREV) || | |
| 1863 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | !(table->file->index_flags(table->s->primary_key, |
| 1864 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
|
102 | used_key_parts_pk - 1, true) & |
| 1865 | HA_READ_PREV))) | ||
| 1866 | ✗ | reverse = 0; // Index can't be used | |
| 1867 | } else { | ||
| 1868 | 58735 | key_parts = (uint)(key_part - table->key_info[idx].key_part); | |
| 1869 |
3/4✓ Branch 0 taken 7799 times.
✓ Branch 1 taken 50936 times.
✓ Branch 2 taken 58735 times.
✗ Branch 3 not taken.
|
66534 | if (reverse == -1 && |
| 1870 |
2/4✓ Branch 0 taken 7799 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7799 times.
|
7799 | !(table->file->index_flags(idx, key_parts - 1, true) & HA_READ_PREV)) |
| 1871 | ✗ | reverse = 0; // Index can't be used | |
| 1872 | } | ||
| 1873 | 58735 | ok: | |
| 1874 |
2/2✓ Branch 0 taken 57612 times.
✓ Branch 1 taken 1305 times.
|
58917 | if (used_key_parts != nullptr) *used_key_parts = key_parts; |
| 1875 | 58917 | return reverse; | |
| 1876 | 70260 | } | |
| 1877 | |||
| 1878 | /** | ||
| 1879 | Find shortest key suitable for full table scan. | ||
| 1880 | |||
| 1881 | @param table Table to scan | ||
| 1882 | @param usable_keys Allowed keys | ||
| 1883 | |||
| 1884 | @note | ||
| 1885 | As far as | ||
| 1886 | 1) clustered primary key entry data set is a set of all record | ||
| 1887 | fields (key fields and not key fields) and | ||
| 1888 | 2) secondary index entry data is a union of its key fields and | ||
| 1889 | primary key fields (at least InnoDB and its derivatives don't | ||
| 1890 | duplicate primary key fields there, even if the primary and | ||
| 1891 | the secondary keys have a common subset of key fields), | ||
| 1892 | then secondary index entry data is always a subset of primary key entry. | ||
| 1893 | Unfortunately, key_info[nr].key_length doesn't show the length | ||
| 1894 | of key/pointer pair but a sum of key field lengths only, thus | ||
| 1895 | we can't estimate index IO volume comparing only this key_length | ||
| 1896 | value of secondary keys and clustered PK. | ||
| 1897 | So, try secondary keys first, and choose PK only if there are no | ||
| 1898 | usable secondary covering keys or found best secondary key include | ||
| 1899 | all table fields (i.e. same as PK): | ||
| 1900 | |||
| 1901 | @return | ||
| 1902 | MAX_KEY no suitable key found | ||
| 1903 | key index otherwise | ||
| 1904 | */ | ||
| 1905 | |||
| 1906 | 1816723 | uint find_shortest_key(TABLE *table, const Key_map *usable_keys) { | |
| 1907 | 1816723 | uint best = MAX_KEY; | |
| 1908 | 1816723 | uint usable_clustered_pk = (table->file->primary_key_is_clustered() && | |
| 1909 |
4/4✓ Branch 0 taken 850565 times.
✓ Branch 1 taken 309866 times.
✓ Branch 2 taken 458322 times.
✓ Branch 3 taken 392236 times.
|
2010989 | table->s->primary_key != MAX_KEY && |
| 1910 | 850565 | usable_keys->is_set(table->s->primary_key)) | |
| 1911 |
2/2✓ Branch 0 taken 1160431 times.
✓ Branch 1 taken 656313 times.
|
2977168 | ? table->s->primary_key |
| 1912 | 1816737 | : MAX_KEY; | |
| 1913 |
2/2✓ Branch 0 taken 626570 times.
✓ Branch 1 taken 1190167 times.
|
1816737 | if (!usable_keys->is_clear_all()) { |
| 1914 | 626570 | uint min_length = (uint)~0; | |
| 1915 |
2/2✓ Branch 0 taken 1019163 times.
✓ Branch 1 taken 626570 times.
|
1645733 | for (uint nr = 0; nr < table->s->keys; nr++) { |
| 1916 |
2/2✓ Branch 0 taken 458324 times.
✓ Branch 1 taken 560839 times.
|
1019163 | if (nr == usable_clustered_pk) continue; |
| 1917 |
2/2✓ Branch 0 taken 389996 times.
✓ Branch 1 taken 170843 times.
|
560839 | if (usable_keys->is_set(nr)) { |
| 1918 | /* | ||
| 1919 | Can not do full index scan on rtree index because it is not | ||
| 1920 | supported by Innodb, probably not supported by others either. | ||
| 1921 | A multi-valued key requires unique filter, and won't be the most | ||
| 1922 | fast option even if it will be the shortest one. | ||
| 1923 | */ | ||
| 1924 | 389996 | const KEY &key_ref = table->key_info[nr]; | |
| 1925 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 389996 times.
|
389996 | assert(!(key_ref.flags & HA_MULTI_VALUED_KEY)); |
| 1926 |
4/4✓ Branch 0 taken 383944 times.
✓ Branch 1 taken 6052 times.
✓ Branch 2 taken 382080 times.
✓ Branch 3 taken 1864 times.
|
389996 | if (key_ref.key_length < min_length && !(key_ref.flags & HA_SPATIAL)) { |
| 1927 | 382080 | min_length = key_ref.key_length; | |
| 1928 | 382080 | best = nr; | |
| 1929 | } | ||
| 1930 | } | ||
| 1931 | } | ||
| 1932 | } | ||
| 1933 |
2/2✓ Branch 0 taken 458331 times.
✓ Branch 1 taken 1358406 times.
|
1816737 | if (usable_clustered_pk != MAX_KEY) { |
| 1934 | /* | ||
| 1935 | If the primary key is clustered and found shorter key covers all table | ||
| 1936 | fields and is not clustering then primary key scan normally would be | ||
| 1937 | faster because amount of data to scan is the same but PK is clustered. | ||
| 1938 | It's safe to compare key parts with table fields since duplicate key | ||
| 1939 | parts aren't allowed. | ||
| 1940 | */ | ||
| 1941 |
4/4✓ Branch 0 taken 213270 times.
✓ Branch 1 taken 245061 times.
✓ Branch 2 taken 245126 times.
✓ Branch 3 taken 213205 times.
|
671601 | if (best == MAX_KEY || |
| 1942 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 213205 times.
|
213270 | ((table->key_info[best].user_defined_key_parts >= table->s->fields) && |
| 1943 |
1/2✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
|
65 | !(table->file->index_flags(best, 0, 0) & HA_CLUSTERED_INDEX))) |
| 1944 | 245126 | best = usable_clustered_pk; | |
| 1945 | } | ||
| 1946 | 1816737 | return best; | |
| 1947 | } | ||
| 1948 | |||
| 1949 | /** | ||
| 1950 | Test if a second key is the subkey of the first one. | ||
| 1951 | |||
| 1952 | @param key_part First key parts | ||
| 1953 | @param ref_key_part Second key parts | ||
| 1954 | @param ref_key_part_end Last+1 part of the second key | ||
| 1955 | |||
| 1956 | @note | ||
| 1957 | Second key MUST be shorter than the first one. | ||
| 1958 | |||
| 1959 | @retval | ||
| 1960 | 1 is a subkey | ||
| 1961 | @retval | ||
| 1962 | 0 no sub key | ||
| 1963 | */ | ||
| 1964 | |||
| 1965 | 554 | inline bool is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part, | |
| 1966 | KEY_PART_INFO *ref_key_part_end) { | ||
| 1967 |
2/2✓ Branch 0 taken 554 times.
✓ Branch 1 taken 349 times.
|
903 | for (; ref_key_part < ref_key_part_end; key_part++, ref_key_part++) |
| 1968 |
2/2✓ Branch 0 taken 205 times.
✓ Branch 1 taken 349 times.
|
554 | if (!key_part->field->eq(ref_key_part->field)) return false; |
| 1969 | 349 | return true; | |
| 1970 | } | ||
| 1971 | |||
| 1972 | /** | ||
| 1973 | Test if REF_OR_NULL optimization will be used if the specified | ||
| 1974 | ref_key is used for REF-access to 'tab' | ||
| 1975 | |||
| 1976 | @retval | ||
| 1977 | true JT_REF_OR_NULL will be used | ||
| 1978 | @retval | ||
| 1979 | false no JT_REF_OR_NULL access | ||
| 1980 | */ | ||
| 1981 | |||
| 1982 | 349 | static bool is_ref_or_null_optimized(const JOIN_TAB *tab, uint ref_key) { | |
| 1983 |
2/2✓ Branch 0 taken 328 times.
✓ Branch 1 taken 21 times.
|
349 | if (tab->keyuse()) { |
| 1984 | 328 | const Key_use *keyuse = tab->keyuse(); | |
| 1985 |
3/4✓ Branch 0 taken 272 times.
✓ Branch 1 taken 328 times.
✓ Branch 2 taken 272 times.
✗ Branch 3 not taken.
|
600 | while (keyuse->key != ref_key && keyuse->table_ref == tab->table_ref) |
| 1986 | 272 | keyuse++; | |
| 1987 | |||
| 1988 | 328 | const table_map const_tables = tab->join()->const_table_map; | |
| 1989 |
3/4✓ Branch 0 taken 360 times.
✓ Branch 1 taken 296 times.
✓ Branch 2 taken 360 times.
✗ Branch 3 not taken.
|
656 | while (keyuse->key == ref_key && keyuse->table_ref == tab->table_ref) { |
| 1990 |
1/2✓ Branch 0 taken 360 times.
✗ Branch 1 not taken.
|
360 | if (!(keyuse->used_tables & ~const_tables)) { |
| 1991 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 328 times.
|
360 | if (keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL) return true; |
| 1992 | } | ||
| 1993 | 328 | keyuse++; | |
| 1994 | } | ||
| 1995 | } | ||
| 1996 | 317 | return false; | |
| 1997 | } | ||
| 1998 | |||
| 1999 | /** | ||
| 2000 | Test if we can use one of the 'usable_keys' instead of 'ref' key | ||
| 2001 | for sorting. | ||
| 2002 | |||
| 2003 | @param order The query block's order clause. | ||
| 2004 | @param tab Current JOIN_TAB. | ||
| 2005 | @param ref Number of key, used for WHERE clause | ||
| 2006 | @param ref_key_parts Index columns used for ref lookup. | ||
| 2007 | @param usable_keys Keys for testing | ||
| 2008 | |||
| 2009 | @return | ||
| 2010 | - MAX_KEY If we can't use other key | ||
| 2011 | - the number of found key Otherwise | ||
| 2012 | */ | ||
| 2013 | |||
| 2014 | 539 | static uint test_if_subkey(ORDER_with_src *order, JOIN_TAB *tab, uint ref, | |
| 2015 | uint ref_key_parts, const Key_map *usable_keys) { | ||
| 2016 | uint nr; | ||
| 2017 | 539 | uint min_length = (uint)~0; | |
| 2018 | 539 | uint best = MAX_KEY; | |
| 2019 | 539 | TABLE *table = tab->table(); | |
| 2020 | 539 | KEY_PART_INFO *ref_key_part = table->key_info[ref].key_part; | |
| 2021 | 539 | KEY_PART_INFO *ref_key_part_end = ref_key_part + ref_key_parts; | |
| 2022 | |||
| 2023 |
2/2✓ Branch 0 taken 2146 times.
✓ Branch 1 taken 539 times.
|
2685 | for (nr = 0; nr < table->s->keys; nr++) { |
| 2024 | bool skip_quick; | ||
| 2025 | 2146 | if (usable_keys->is_set(nr) && | |
| 2026 |
2/2✓ Branch 0 taken 554 times.
✓ Branch 1 taken 2 times.
|
556 | table->key_info[nr].key_length < min_length && |
| 2027 |
1/2✓ Branch 0 taken 554 times.
✗ Branch 1 not taken.
|
554 | table->key_info[nr].user_defined_key_parts >= ref_key_parts && |
| 2028 |
3/4✓ Branch 0 taken 554 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 349 times.
✓ Branch 3 taken 205 times.
|
554 | is_subkey(table->key_info[nr].key_part, ref_key_part, |
| 2029 | 349 | ref_key_part_end) && | |
| 2030 |
2/2✓ Branch 0 taken 317 times.
✓ Branch 1 taken 32 times.
|
349 | !is_ref_or_null_optimized(tab, nr) && |
| 2031 |
7/8✓ Branch 0 taken 556 times.
✓ Branch 1 taken 1590 times.
✓ Branch 2 taken 317 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 312 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 312 times.
✓ Branch 7 taken 1834 times.
|
3014 | test_if_order_by_key(order, table, nr, nullptr, &skip_quick) && |
| 2032 |
1/2✓ Branch 0 taken 312 times.
✗ Branch 1 not taken.
|
312 | !skip_quick) { |
| 2033 | 312 | min_length = table->key_info[nr].key_length; | |
| 2034 | 312 | best = nr; | |
| 2035 | } | ||
| 2036 | } | ||
| 2037 | 539 | return best; | |
| 2038 | } | ||
| 2039 | |||
| 2040 | /** | ||
| 2041 | It is not obvious to see that test_if_skip_sort_order() never changes the | ||
| 2042 | plan if no_changes is true. So we double-check: creating an instance of this | ||
| 2043 | class saves some important access-path-related information of the current | ||
| 2044 | table; when the instance is destroyed, the latest access-path information is | ||
| 2045 | compared with saved data. | ||
| 2046 | */ | ||
| 2047 | |||
| 2048 | class Plan_change_watchdog { | ||
| 2049 | #ifndef NDEBUG | ||
| 2050 | public: | ||
| 2051 | /** | ||
| 2052 | @param tab_arg table whose access path is being determined | ||
| 2053 | @param no_changes_arg whether a change to the access path is allowed | ||
| 2054 | */ | ||
| 2055 | 367758 | Plan_change_watchdog(const JOIN_TAB *tab_arg, const bool no_changes_arg) { | |
| 2056 |
2/2✓ Branch 0 taken 325 times.
✓ Branch 1 taken 367433 times.
|
367758 | if (no_changes_arg) { |
| 2057 | 325 | tab = tab_arg; | |
| 2058 | 325 | type = tab->type(); | |
| 2059 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 316 times.
|
325 | if ((quick = tab->range_scan())) quick_index = used_index(quick); |
| 2060 | 325 | use_quick = tab->use_quick; | |
| 2061 | 325 | ref_key = tab->ref().key; | |
| 2062 | 325 | ref_key_parts = tab->ref().key_parts; | |
| 2063 | 325 | index = tab->index(); | |
| 2064 | } else { | ||
| 2065 | 367433 | tab = nullptr; | |
| 2066 | 367433 | type = JT_UNKNOWN; | |
| 2067 | 367433 | quick = nullptr; | |
| 2068 | 367433 | ref_key = ref_key_parts = index = 0; | |
| 2069 | 367433 | use_quick = QS_NONE; | |
| 2070 | } | ||
| 2071 | 367758 | } | |
| 2072 | 368083 | ~Plan_change_watchdog() { | |
| 2073 |
2/2✓ Branch 0 taken 367433 times.
✓ Branch 1 taken 325 times.
|
367758 | if (tab == nullptr) return; |
| 2074 | // changes are not allowed, we verify: | ||
| 2075 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
|
325 | assert(tab->type() == type); |
| 2076 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
|
325 | assert(tab->range_scan() == quick); |
| 2077 |
3/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
|
325 | assert(quick == nullptr || used_index(tab->range_scan()) == quick_index); |
| 2078 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
|
325 | assert(tab->use_quick == use_quick); |
| 2079 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
|
325 | assert(tab->ref().key == ref_key); |
| 2080 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
|
325 | assert(tab->ref().key_parts == ref_key_parts); |
| 2081 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
|
325 | assert(tab->index() == index); |
| 2082 | 367758 | } | |
| 2083 | |||
| 2084 | private: | ||
| 2085 | const JOIN_TAB *tab; ///< table, or NULL if changes are allowed | ||
| 2086 | enum join_type type; ///< copy of tab->type() | ||
| 2087 | // "Range / index merge" info | ||
| 2088 | const AccessPath *quick{nullptr}; ///< copy of tab->select->quick | ||
| 2089 | uint quick_index{0}; ///< copy of tab->select->quick->index | ||
| 2090 | enum quick_type use_quick; ///< copy of tab->use_quick | ||
| 2091 | // "ref access" info | ||
| 2092 | int ref_key; ///< copy of tab->ref().key | ||
| 2093 | uint ref_key_parts; /// copy of tab->ref().key_parts | ||
| 2094 | // Other index-related info | ||
| 2095 | uint index; ///< copy of tab->index | ||
| 2096 | #else // in non-debug build, empty class | ||
| 2097 | public: | ||
| 2098 | Plan_change_watchdog(const JOIN_TAB *, const bool) {} | ||
| 2099 | #endif | ||
| 2100 | }; | ||
| 2101 | |||
| 2102 | /** | ||
| 2103 | Test if we can skip ordering by using an index. | ||
| 2104 | |||
| 2105 | If the current plan is to use an index that provides ordering, the | ||
| 2106 | plan will not be changed. Otherwise, if an index can be used, the | ||
| 2107 | JOIN_TAB / tab->select struct is changed to use the index. | ||
| 2108 | |||
| 2109 | The index must cover all fields in @<order@>, or it will not be considered. | ||
| 2110 | |||
| 2111 | @param tab NULL or JOIN_TAB of the accessed table | ||
| 2112 | @param order Linked list of ORDER BY arguments | ||
| 2113 | @param select_limit LIMIT value, or HA_POS_ERROR if no limit | ||
| 2114 | @param no_changes No changes will be made to the query plan. | ||
| 2115 | @param map Key_map of applicable indexes. | ||
| 2116 | @param [out] order_idx Number of index selected, -1 if no applicable index | ||
| 2117 | found | ||
| 2118 | |||
| 2119 | @todo | ||
| 2120 | - sergeyp: Results of all index merge selects actually are ordered | ||
| 2121 | by clustered PK values. | ||
| 2122 | |||
| 2123 | @note | ||
| 2124 | This function may change tmp_table_param.precomputed_group_by. This | ||
| 2125 | affects how create_tmp_table() treats aggregation functions, so | ||
| 2126 | count_field_types() must be called again to make sure this is taken | ||
| 2127 | into consideration. | ||
| 2128 | |||
| 2129 | @retval | ||
| 2130 | 0 We have to use filesort to do the sorting | ||
| 2131 | @retval | ||
| 2132 | 1 We can use an index. | ||
| 2133 | */ | ||
| 2134 | |||
| 2135 | 367758 | static bool test_if_skip_sort_order(JOIN_TAB *tab, ORDER_with_src &order, | |
| 2136 | ha_rows select_limit, const bool no_changes, | ||
| 2137 | const Key_map *map, int *order_idx) { | ||
| 2138 |
1/2✓ Branch 0 taken 367758 times.
✗ Branch 1 not taken.
|
367758 | DBUG_TRACE; |
| 2139 | int ref_key; | ||
| 2140 | 367758 | uint ref_key_parts = 0; | |
| 2141 | 367758 | int order_direction = 0; | |
| 2142 | 367758 | uint used_key_parts = 0; | |
| 2143 | 367758 | TABLE *const table = tab->table(); | |
| 2144 | 367758 | JOIN *const join = tab->join(); | |
| 2145 | 367758 | THD *const thd = join->thd; | |
| 2146 | 367758 | AccessPath *const save_range_scan = tab->range_scan(); | |
| 2147 | 367758 | int best_key = -1; | |
| 2148 | 367758 | bool set_up_ref_access_to_key = false; | |
| 2149 | 367758 | bool can_skip_sorting = false; // used as return value | |
| 2150 | 367758 | int changed_key = -1; | |
| 2151 | |||
| 2152 | /* Check that we are always called with first non-const table */ | ||
| 2153 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 367758 times.
|
367758 | assert((uint)tab->idx() == join->const_tables); |
| 2154 | |||
| 2155 | 367758 | Plan_change_watchdog watchdog(tab, no_changes); | |
| 2156 | 367758 | *order_idx = -1; | |
| 2157 | /* Sorting a single row can always be skipped */ | ||
| 2158 |
6/8✓ Branch 0 taken 367758 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 367757 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 367757 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 367757 times.
|
735515 | if (tab->type() == JT_EQ_REF || tab->type() == JT_CONST || |
| 2159 | 367757 | tab->type() == JT_SYSTEM) { | |
| 2160 | 1 | return true; | |
| 2161 | } | ||
| 2162 | |||
| 2163 | /* | ||
| 2164 | Check if FT index can be used to retrieve result in the required order. | ||
| 2165 | It is possible if ordering is on the first non-constant table. | ||
| 2166 | */ | ||
| 2167 |
6/6✓ Branch 0 taken 358011 times.
✓ Branch 1 taken 9746 times.
✓ Branch 2 taken 357769 times.
✓ Branch 3 taken 242 times.
✓ Branch 4 taken 357769 times.
✓ Branch 5 taken 9988 times.
|
367757 | if (!join->order.empty() && join->simple_order) { |
| 2168 | /* | ||
| 2169 | Check if ORDER is DESC, ORDER BY is a single MATCH function. | ||
| 2170 | */ | ||
| 2171 |
1/2✓ Branch 0 taken 357769 times.
✗ Branch 1 not taken.
|
357769 | Item_func_match *ft_func = test_if_ft_index_order(order.order); |
| 2172 | /* | ||
| 2173 | Two possible cases when we can skip sort order: | ||
| 2174 | 1. FT_SORTED must be set(Natural mode, no ORDER BY). | ||
| 2175 | 2. If FT_SORTED flag is not set then | ||
| 2176 | the engine should support deferred sorting. Deferred sorting means | ||
| 2177 | that sorting is postponed utill the start of index reading(InnoDB). | ||
| 2178 | In this case we set FT_SORTED flag here to let the engine know that | ||
| 2179 | internal sorting is needed. | ||
| 2180 | */ | ||
| 2181 |
9/10✓ Branch 0 taken 51 times.
✓ Branch 1 taken 357718 times.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 49 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 45 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 45 times.
✓ Branch 9 taken 357724 times.
|
357769 | if (ft_func && ft_func->ft_handler && ft_func->ordered_result()) { |
| 2182 | /* | ||
| 2183 | FT index scan is used, so the only additional requirement is | ||
| 2184 | that ORDER BY MATCH function is the same as the function that | ||
| 2185 | is used for FT index. | ||
| 2186 | */ | ||
| 2187 |
4/4✓ Branch 0 taken 26 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 24 times.
|
71 | if (tab->type() == JT_FT && |
| 2188 |
3/4✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 5 times.
|
26 | ft_func->eq(tab->position()->key->val, true)) { |
| 2189 |
1/2✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
|
21 | ft_func->set_hints(join, FT_SORTED, select_limit, false); |
| 2190 | 21 | return true; | |
| 2191 | } | ||
| 2192 | /* | ||
| 2193 | No index is used, it's possible to use FT index for ORDER BY if | ||
| 2194 | LIMIT is present and does not exceed count of the records in FT index | ||
| 2195 | and there is no WHERE condition since a condition may potentially | ||
| 2196 | require more rows to be fetch from FT index. | ||
| 2197 | */ | ||
| 2198 |
6/6✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 14 times.
|
36 | if (!tab->condition() && select_limit != HA_POS_ERROR && |
| 2199 |
3/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 2 times.
|
12 | select_limit <= ft_func->get_count()) { |
| 2200 | /* test_if_ft_index_order() always returns master MATCH function. */ | ||
| 2201 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | assert(!ft_func->master); |
| 2202 | /* ref is not set since there is no WHERE condition */ | ||
| 2203 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | assert(tab->ref().key == -1); |
| 2204 | |||
| 2205 | /*Make EXPLAIN happy */ | ||
| 2206 | 10 | tab->set_type(JT_FT); | |
| 2207 | 10 | tab->ref().key = ft_func->key; | |
| 2208 | 10 | tab->ref().key_parts = 0; | |
| 2209 | 10 | tab->set_index(ft_func->key); | |
| 2210 | 10 | tab->set_ft_func(ft_func); | |
| 2211 | |||
| 2212 | /* Setup FT handler */ | ||
| 2213 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | ft_func->set_hints(join, FT_SORTED, select_limit, true); |
| 2214 | 10 | ft_func->score_from_index_scan = true; | |
| 2215 | 10 | table->file->ft_handler = ft_func->ft_handler; | |
| 2216 | 10 | return true; | |
| 2217 | } | ||
| 2218 | } | ||
| 2219 | } | ||
| 2220 | |||
| 2221 | /* | ||
| 2222 | Keys disabled by ALTER TABLE ... DISABLE KEYS should have already | ||
| 2223 | been taken into account. | ||
| 2224 | */ | ||
| 2225 | 367726 | Key_map usable_keys = *map; | |
| 2226 | |||
| 2227 |
2/2✓ Branch 0 taken 383868 times.
✓ Branch 1 taken 56891 times.
|
440759 | for (ORDER *tmp_order = order.order; tmp_order; tmp_order = tmp_order->next) { |
| 2228 |
1/2✓ Branch 0 taken 383868 times.
✗ Branch 1 not taken.
|
383868 | const Item *item = (*tmp_order->item)->real_item(); |
| 2229 |
3/4✓ Branch 0 taken 383868 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3628 times.
✓ Branch 3 taken 380240 times.
|
383868 | if (item->type() != Item::FIELD_ITEM) { |
| 2230 | 3628 | usable_keys.clear_all(); | |
| 2231 | 3628 | return false; | |
| 2232 | } | ||
| 2233 | 380240 | usable_keys.intersect( | |
| 2234 | 380240 | down_cast<const Item_field *>(item)->field->part_of_sortkey); | |
| 2235 |
2/2✓ Branch 0 taken 307207 times.
✓ Branch 1 taken 73033 times.
|
380240 | if (usable_keys.is_clear_all()) return false; // No usable keys |
| 2236 | } | ||
| 2237 |
6/6✓ Branch 0 taken 56888 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 56859 times.
✓ Branch 4 taken 32 times.
✓ Branch 5 taken 56859 times.
|
56891 | if (tab->type() == JT_REF_OR_NULL || tab->type() == JT_FT) return false; |
| 2238 | |||
| 2239 | 56859 | ref_key = -1; | |
| 2240 | /* Test if constant range in WHERE */ | ||
| 2241 |
2/2✓ Branch 0 taken 2303 times.
✓ Branch 1 taken 54556 times.
|
56859 | if (tab->type() == JT_REF) { |
| 2242 |
2/4✓ Branch 0 taken 2303 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2303 times.
✗ Branch 3 not taken.
|
2303 | assert(tab->ref().key >= 0 && tab->ref().key_parts); |
| 2243 | 2303 | ref_key = tab->ref().key; | |
| 2244 | 2303 | ref_key_parts = tab->ref().key_parts; | |
| 2245 |
6/6✓ Branch 0 taken 47781 times.
✓ Branch 1 taken 6775 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 47731 times.
✓ Branch 4 taken 6825 times.
✓ Branch 5 taken 47731 times.
|
54556 | } else if (tab->type() == JT_RANGE || tab->type() == JT_INDEX_MERGE) { |
| 2246 | // Range found by opt_range | ||
| 2247 | /* | ||
| 2248 | assume results are not ordered when index merge is used | ||
| 2249 | TODO: sergeyp: Results of all index merge selects actually are ordered | ||
| 2250 | by clustered PK values. | ||
| 2251 | */ | ||
| 2252 | |||
| 2253 | 6825 | if (tab->range_scan()->type == AccessPath::INDEX_MERGE || | |
| 2254 |
6/6✓ Branch 0 taken 6795 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 6787 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 50 times.
✓ Branch 5 taken 6775 times.
|
13612 | tab->range_scan()->type == AccessPath::ROWID_UNION || |
| 2255 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6775 times.
|
6787 | tab->range_scan()->type == AccessPath::ROWID_INTERSECTION) |
| 2256 | 50 | return false; | |
| 2257 | 6775 | ref_key = used_index(tab->range_scan()); | |
| 2258 | 6775 | ref_key_parts = get_used_key_parts(tab->range_scan()); | |
| 2259 |
2/2✓ Branch 0 taken 3641 times.
✓ Branch 1 taken 44090 times.
|
47731 | } else if (tab->type() == JT_INDEX_SCAN) { |
| 2260 | // The optimizer has decided to use an index scan. | ||
| 2261 | 3641 | ref_key = tab->index(); | |
| 2262 |
1/2✓ Branch 0 taken 3641 times.
✗ Branch 1 not taken.
|
3641 | ref_key_parts = actual_key_parts(&table->key_info[tab->index()]); |
| 2263 | } | ||
| 2264 | |||
| 2265 | 56809 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 2266 |
1/2✓ Branch 0 taken 56809 times.
✗ Branch 1 not taken.
|
56809 | Opt_trace_object trace_wrapper_1(trace); |
| 2267 | Opt_trace_object trace_skip_sort_order( | ||
| 2268 |
1/2✓ Branch 0 taken 56809 times.
✗ Branch 1 not taken.
|
56809 | trace, "reconsidering_access_paths_for_index_ordering"); |
| 2269 |
1/2✓ Branch 0 taken 56809 times.
✗ Branch 1 not taken.
|
56809 | trace_skip_sort_order.add_alnum( |
| 2270 |
2/2✓ Branch 0 taken 55192 times.
✓ Branch 1 taken 1617 times.
|
56809 | "clause", (order.src == ESC_ORDER_BY ? "ORDER BY" : "GROUP BY")); |
| 2271 |
1/2✓ Branch 0 taken 56809 times.
✗ Branch 1 not taken.
|
56809 | Opt_trace_array trace_steps(trace, "steps"); |
| 2272 | |||
| 2273 |
2/2✓ Branch 0 taken 12719 times.
✓ Branch 1 taken 44090 times.
|
56809 | if (ref_key >= 0) { |
| 2274 | /* | ||
| 2275 | We come here when ref/index scan/range scan access has been set | ||
| 2276 | up for this table. Do not change access method if ordering is | ||
| 2277 | provided already. | ||
| 2278 | */ | ||
| 2279 |
2/2✓ Branch 0 taken 539 times.
✓ Branch 1 taken 12180 times.
|
12719 | if (!usable_keys.is_set(ref_key)) { |
| 2280 | /* | ||
| 2281 | We come here when ref_key is not among usable_keys, try to find a | ||
| 2282 | usable prefix key of that key. | ||
| 2283 | */ | ||
| 2284 | uint new_ref_key; | ||
| 2285 | /* | ||
| 2286 | If using index only read, only consider other possible index only | ||
| 2287 | keys | ||
| 2288 | */ | ||
| 2289 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 538 times.
|
539 | if (table->covering_keys.is_set(ref_key)) |
| 2290 | 1 | usable_keys.intersect(table->covering_keys); | |
| 2291 | |||
| 2292 |
1/2✓ Branch 0 taken 539 times.
✗ Branch 1 not taken.
|
539 | if ((new_ref_key = test_if_subkey(&order, tab, ref_key, ref_key_parts, |
| 2293 |
2/2✓ Branch 0 taken 312 times.
✓ Branch 1 taken 227 times.
|
539 | &usable_keys)) < MAX_KEY) { |
| 2294 | /* Found key that can be used to retrieve data in sorted order */ | ||
| 2295 |
2/2✓ Branch 0 taken 296 times.
✓ Branch 1 taken 16 times.
|
312 | if (tab->ref().key >= 0) { |
| 2296 | /* | ||
| 2297 | We'll use ref access method on key new_ref_key. The actual change | ||
| 2298 | is done further down in this function where we update the plan. | ||
| 2299 | */ | ||
| 2300 | 296 | set_up_ref_access_to_key = true; | |
| 2301 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
|
16 | } else if (!no_changes) { |
| 2302 | /* | ||
| 2303 | The range optimizer constructed QUICK_RANGE for ref_key, and | ||
| 2304 | we want to use instead new_ref_key as the index. We can't | ||
| 2305 | just change the index of the quick select, because this may | ||
| 2306 | result in an inconsistent RowIterator object. Below we | ||
| 2307 | create a new RowIterator from scratch so that all its | ||
| 2308 | parameres are set correctly by the range optimizer. | ||
| 2309 | |||
| 2310 | Note that the range optimizer is NOT called if | ||
| 2311 | no_changes==true. This reason is that the range optimizer | ||
| 2312 | cannot find a QUICK that can return ordered result unless | ||
| 2313 | index access (ref or index scan) is also able to do so | ||
| 2314 | (which test_if_order_by_key () will tell). | ||
| 2315 | Admittedly, range access may be much more efficient than | ||
| 2316 | e.g. index scan, but the only thing that matters when | ||
| 2317 | no_change==true is the answer to the question: "Is it | ||
| 2318 | possible to avoid sorting if an index is used to access | ||
| 2319 | this table?". The answer does not depend on the outcome of | ||
| 2320 | the range optimizer. | ||
| 2321 | */ | ||
| 2322 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | Key_map new_ref_key_map; // Force the creation of quick select |
| 2323 | 14 | new_ref_key_map.set_bit(new_ref_key); // only for new_ref_key. | |
| 2324 | |||
| 2325 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | Opt_trace_object trace_wrapper_2(trace); |
| 2326 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | Opt_trace_object trace_recest(trace, "rows_estimation"); |
| 2327 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | trace_recest.add_utf8_table(tab->table_ref) |
| 2328 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | .add_utf8("index", table->key_info[new_ref_key].name); |
| 2329 | AccessPath *range_scan; | ||
| 2330 | MEM_ROOT temp_mem_root(key_memory_test_quick_select_exec, | ||
| 2331 | 14 | thd->variables.range_alloc_block_size); | |
| 2332 | const bool no_quick = | ||
| 2333 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
28 | test_quick_select( |
| 2334 | thd, thd->mem_root, &temp_mem_root, new_ref_key_map, 0, | ||
| 2335 | 0, // empty table_map | ||
| 2336 | 14 | join->calc_found_rows | |
| 2337 | ? HA_POS_ERROR | ||
| 2338 | 14 | : join->query_expression()->select_limit_cnt, | |
| 2339 | false, // don't force quick range | ||
| 2340 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | order.order->direction, tab->table(), |
| 2341 | 14 | tab->skip_records_in_range(), | |
| 2342 | // we are after make_join_query_block(): | ||
| 2343 | 14 | tab->condition(), &tab->needed_reg, tab->table()->force_index, | |
| 2344 | 14 | join->query_block, &range_scan) <= 0; | |
| 2345 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | assert(tab->range_scan() == save_range_scan); |
| 2346 | 14 | tab->set_range_scan(range_scan); | |
| 2347 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
|
14 | if (no_quick) { |
| 2348 | 3 | can_skip_sorting = false; | |
| 2349 | 3 | goto fix_ICP; | |
| 2350 | } | ||
| 2351 |
6/6✓ Branch 0 taken 11 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 3 times.
|
20 | } |
| 2352 | 309 | ref_key = new_ref_key; | |
| 2353 | 309 | changed_key = new_ref_key; | |
| 2354 | } | ||
| 2355 | } | ||
| 2356 | bool dummy; | ||
| 2357 | /* Check if we get the rows in requested sorted order by using the key */ | ||
| 2358 |
2/2✓ Branch 0 taken 12489 times.
✓ Branch 1 taken 227 times.
|
12716 | if (usable_keys.is_set(ref_key)) |
| 2359 | // Last parameter can be ignored as it'll be checked later, if needed | ||
| 2360 | order_direction = | ||
| 2361 |
1/2✓ Branch 0 taken 12489 times.
✗ Branch 1 not taken.
|
12489 | test_if_order_by_key(&order, table, ref_key, &used_key_parts, &dummy); |
| 2362 | } | ||
| 2363 |
4/4✓ Branch 0 taken 12716 times.
✓ Branch 1 taken 44090 times.
✓ Branch 2 taken 5725 times.
✓ Branch 3 taken 6991 times.
|
56806 | if (ref_key < 0 || order_direction <= 0) { |
| 2364 | /* | ||
| 2365 | There is no ref/index scan/range scan access set up for this | ||
| 2366 | table, or it does not provide the requested ordering, or it uses | ||
| 2367 | backward scan. Do a cost-based search on all keys. | ||
| 2368 | */ | ||
| 2369 | 49815 | uint best_key_parts = 0; | |
| 2370 | 49815 | uint saved_best_key_parts = 0; | |
| 2371 | 49815 | int best_key_direction = 0; | |
| 2372 | 49815 | ha_rows table_records = table->file->stats.records; | |
| 2373 | |||
| 2374 | /* | ||
| 2375 | If an index scan that cannot provide ordering has been selected | ||
| 2376 | then do not use the index scan key as starting hint to | ||
| 2377 | test_if_cheaper_ordering() | ||
| 2378 | */ | ||
| 2379 | const int ref_key_hint = | ||
| 2380 |
4/4✓ Branch 0 taken 47060 times.
✓ Branch 1 taken 2755 times.
✓ Branch 2 taken 45862 times.
✓ Branch 3 taken 1198 times.
|
49815 | (order_direction == 0 && tab->type() == JT_INDEX_SCAN) ? -1 : ref_key; |
| 2381 | |||
| 2382 | // Does the query have a "FORCE INDEX [FOR GROUP BY] (idx)" (if clause is | ||
| 2383 | // group by) or a "FORCE INDEX [FOR ORDER BY] (idx)" (if clause is order | ||
| 2384 | // by)? | ||
| 2385 | 49815 | const bool is_group_by = | |
| 2386 |
4/6✓ Branch 0 taken 49815 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 329 times.
✓ Branch 3 taken 49486 times.
✓ Branch 4 taken 329 times.
✗ Branch 5 not taken.
|
49815 | join && join->grouped && order.order == join->group_list.order; |
| 2387 | 49815 | const bool is_force_index = | |
| 2388 |
4/4✓ Branch 0 taken 48959 times.
✓ Branch 1 taken 856 times.
✓ Branch 2 taken 317 times.
✓ Branch 3 taken 48642 times.
|
98774 | table->force_index || |
| 2389 |
4/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 315 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 48639 times.
|
48959 | (is_group_by ? table->force_index_group : table->force_index_order); |
| 2390 | |||
| 2391 | // Find an ordering index alternative over the chosen plan iff | ||
| 2392 | // prefer_ordering_index switch is on. This switch is overridden only when | ||
| 2393 | // force index for order/group is specified. | ||
| 2394 |
6/6✓ Branch 0 taken 10 times.
✓ Branch 1 taken 49805 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 49807 times.
✓ Branch 5 taken 8 times.
|
49815 | if (thd->optimizer_switch_flag(OPTIMIZER_SWITCH_PREFER_ORDERING_INDEX) || |
| 2395 | is_force_index) | ||
| 2396 |
1/2✓ Branch 0 taken 49807 times.
✗ Branch 1 not taken.
|
49807 | test_if_cheaper_ordering(tab, &order, table, usable_keys, ref_key_hint, |
| 2397 | select_limit, &best_key, &best_key_direction, | ||
| 2398 | &select_limit, &best_key_parts, | ||
| 2399 | &saved_best_key_parts); | ||
| 2400 | |||
| 2401 | // Try backward scan for previously found key | ||
| 2402 |
4/4✓ Branch 0 taken 36871 times.
✓ Branch 1 taken 12944 times.
✓ Branch 2 taken 2743 times.
✓ Branch 3 taken 34128 times.
|
49815 | if (best_key < 0 && order_direction < 0) goto check_reverse_order; |
| 2403 | |||
| 2404 |
2/2✓ Branch 0 taken 34128 times.
✓ Branch 1 taken 12944 times.
|
47072 | if (best_key < 0) { |
| 2405 | // No usable key has been found | ||
| 2406 | 34128 | can_skip_sorting = false; | |
| 2407 | 34150 | goto fix_ICP; | |
| 2408 | } | ||
| 2409 | /* | ||
| 2410 | If found index will use backward index scan, ref_key uses backward | ||
| 2411 | range/ref, pick the latter as it has better selectivity. | ||
| 2412 | */ | ||
| 2413 |
3/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12932 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12944 | if (order_direction < 0 && order_direction == best_key_direction) { |
| 2414 | ✗ | best_key = -1; // reset found best key | |
| 2415 | ✗ | goto check_reverse_order; | |
| 2416 | } | ||
| 2417 | |||
| 2418 | /* | ||
| 2419 | filesort() and join cache are usually faster than reading in | ||
| 2420 | index order and not using join cache. Don't use index scan | ||
| 2421 | unless: | ||
| 2422 | - the user specified FORCE INDEX [FOR {GROUP|ORDER} BY] (have to assume | ||
| 2423 | the user knows what's best) | ||
| 2424 | - the chosen index is clustered primary key (table scan is not cheaper) | ||
| 2425 | */ | ||
| 2426 |
4/4✓ Branch 0 taken 9537 times.
✓ Branch 1 taken 3331 times.
✓ Branch 2 taken 8628 times.
✓ Branch 3 taken 909 times.
|
22405 | if (!is_force_index && (select_limit >= table_records) && |
| 2427 | 9537 | (tab->type() == JT_ALL && | |
| 2428 |
6/6✓ Branch 0 taken 12868 times.
✓ Branch 1 taken 76 times.
✓ Branch 2 taken 71 times.
✓ Branch 3 taken 8557 times.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 12922 times.
|
25883 | join->primary_tables > join->const_tables + 1) && |
| 2429 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 19 times.
|
71 | ((unsigned)best_key != table->s->primary_key || |
| 2430 |
3/4✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 49 times.
|
52 | !table->file->primary_key_is_clustered())) { |
| 2431 | 22 | can_skip_sorting = false; | |
| 2432 | 22 | goto fix_ICP; | |
| 2433 | } | ||
| 2434 | |||
| 2435 | 12922 | if (table->quick_keys.is_set(best_key) && | |
| 2436 |
6/8✓ Branch 0 taken 102 times.
✓ Branch 1 taken 12820 times.
✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 102 times.
✓ Branch 7 taken 12820 times.
|
12922 | !tab->quick_order_tested.is_set(best_key) && best_key != ref_key) { |
| 2437 | 102 | tab->quick_order_tested.set_bit(best_key); | |
| 2438 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | Opt_trace_object trace_wrapper_3(trace); |
| 2439 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | Opt_trace_object trace_recest(trace, "rows_estimation"); |
| 2440 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | trace_recest.add_utf8_table(tab->table_ref) |
| 2441 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | .add_utf8("index", table->key_info[best_key].name); |
| 2442 | |||
| 2443 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | Key_map keys_to_use; // Force the creation of quick select |
| 2444 | 102 | keys_to_use.set_bit(best_key); // only best_key. | |
| 2445 | MEM_ROOT temp_mem_root(key_memory_test_quick_select_exec, | ||
| 2446 | 102 | thd->variables.range_alloc_block_size); | |
| 2447 | AccessPath *range_scan; | ||
| 2448 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
204 | test_quick_select( |
| 2449 | thd, thd->mem_root, &temp_mem_root, keys_to_use, 0, | ||
| 2450 | 0, // empty table_map | ||
| 2451 | 102 | join->calc_found_rows ? HA_POS_ERROR | |
| 2452 | 102 | : join->query_expression()->select_limit_cnt, | |
| 2453 | true, // force quick range | ||
| 2454 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
|
204 | order.order->direction, tab->table(), tab->skip_records_in_range(), |
| 2455 | 102 | tab->condition(), &tab->needed_reg, tab->table()->force_index, | |
| 2456 | 102 | join->query_block, &range_scan); | |
| 2457 |
6/8✓ Branch 0 taken 2 times.
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 100 times.
|
104 | if (order_direction < 0 && tab->range_scan() != nullptr && |
| 2458 | 2 | tab->range_scan() != save_range_scan) { | |
| 2459 | /* | ||
| 2460 | We came here in case when 3 indexes are available for quick | ||
| 2461 | select: | ||
| 2462 | 1 - found by join order optimizer (greedy search) and saved in | ||
| 2463 | save_range_scan | ||
| 2464 | 2 - constructed far above, as better suited for order by, but it was | ||
| 2465 | found that it requires backward scan. | ||
| 2466 | 3 - constructed right above | ||
| 2467 | In this case we drop quick #2 as #3 is expected to be better. | ||
| 2468 | */ | ||
| 2469 | 2 | destroy(tab->range_scan()); | |
| 2470 | 2 | tab->set_range_scan(nullptr); | |
| 2471 | } | ||
| 2472 | /* | ||
| 2473 | If tab->range_scan() pointed to another quick than save_range_scan, we | ||
| 2474 | would lose access to it and leak memory. | ||
| 2475 | */ | ||
| 2476 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
102 | assert(tab->range_scan() == save_range_scan || |
| 2477 | tab->range_scan() == nullptr); | ||
| 2478 | 102 | tab->set_range_scan(range_scan); | |
| 2479 |
6/6✓ Branch 0 taken 79 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 78 times.
✓ Branch 5 taken 24 times.
|
102 | if (tab->range_scan() && !no_changes) |
| 2480 |
1/2✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
|
78 | tab->set_type(calc_join_type(tab->range_scan())); |
| 2481 | 102 | } | |
| 2482 | 12922 | order_direction = best_key_direction; | |
| 2483 | /* | ||
| 2484 | saved_best_key_parts is actual number of used keyparts found by the | ||
| 2485 | test_if_order_by_key function. It could differ from keyinfo->key_parts, | ||
| 2486 | thus we have to restore it in case of desc order as it affects | ||
| 2487 | ReverseIndexRangeScanIterator behaviour. | ||
| 2488 | */ | ||
| 2489 | 12922 | used_key_parts = | |
| 2490 |
2/2✓ Branch 0 taken 1411 times.
✓ Branch 1 taken 11511 times.
|
12922 | (order_direction == -1) ? saved_best_key_parts : best_key_parts; |
| 2491 | 12922 | changed_key = best_key; | |
| 2492 | // We will use index scan or range scan: | ||
| 2493 | 12922 | set_up_ref_access_to_key = false; | |
| 2494 | } | ||
| 2495 | |||
| 2496 | 6991 | check_reverse_order: | |
| 2497 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22656 times.
|
22656 | assert(order_direction != 0); |
| 2498 | |||
| 2499 |
2/2✓ Branch 0 taken 4154 times.
✓ Branch 1 taken 18502 times.
|
22656 | if (order_direction == -1) // If ORDER BY ... DESC |
| 2500 | { | ||
| 2501 |
2/2✓ Branch 0 taken 1639 times.
✓ Branch 1 taken 2515 times.
|
4154 | if (tab->range_scan()) { |
| 2502 | /* | ||
| 2503 | Don't reverse the sort order, if it's already done. | ||
| 2504 | (In some cases test_if_order_by_key() can be called multiple times | ||
| 2505 | */ | ||
| 2506 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1639 times.
|
1639 | if (is_reverse_sorted_range(tab->range_scan())) { |
| 2507 | ✗ | can_skip_sorting = true; | |
| 2508 | ✗ | goto fix_ICP; | |
| 2509 | } | ||
| 2510 | // test_if_cheaper_ordering() might disable range scan on current index | ||
| 2511 |
5/6✓ Branch 0 taken 1633 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1633 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1633 times.
✓ Branch 5 taken 6 times.
|
3272 | if (tab->table()->quick_keys.is_set(used_index(tab->range_scan())) && |
| 2512 | 1633 | reverse_sort_possible(tab->range_scan())) | |
| 2513 | 1633 | can_skip_sorting = true; | |
| 2514 | else { | ||
| 2515 | 6 | can_skip_sorting = false; | |
| 2516 | 6 | goto fix_ICP; | |
| 2517 | } | ||
| 2518 | } else { | ||
| 2519 | // Other index access (ref or scan) poses no problem | ||
| 2520 | 2515 | can_skip_sorting = true; | |
| 2521 | } | ||
| 2522 | } else { | ||
| 2523 | // ORDER BY ASC poses no problem | ||
| 2524 | 18502 | can_skip_sorting = true; | |
| 2525 | } | ||
| 2526 | |||
| 2527 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22650 times.
|
22650 | assert(can_skip_sorting); |
| 2528 | |||
| 2529 | /* | ||
| 2530 | Update query plan with access pattern for doing | ||
| 2531 | ordered access according to what we have decided | ||
| 2532 | above. | ||
| 2533 | */ | ||
| 2534 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 22548 times.
|
22650 | if (!no_changes) // We are allowed to update QEP |
| 2535 | { | ||
| 2536 |
2/2✓ Branch 0 taken 284 times.
✓ Branch 1 taken 22264 times.
|
22548 | if (set_up_ref_access_to_key) { |
| 2537 | /* | ||
| 2538 | We'll use ref access method on key changed_key. In general case | ||
| 2539 | the index search tuple for changed_ref_key will be different (e.g. | ||
| 2540 | when one index is defined as (part1, part2, ...) and another as | ||
| 2541 | (part1, part2(N), ...) and the WHERE clause contains | ||
| 2542 | "part1 = const1 AND part2=const2". | ||
| 2543 | So we build tab->ref() from scratch here. | ||
| 2544 | */ | ||
| 2545 | 284 | Key_use *keyuse = tab->keyuse(); | |
| 2546 |
2/2✓ Branch 0 taken 260 times.
✓ Branch 1 taken 284 times.
|
544 | while (keyuse->key != (uint)changed_key && |
| 2547 |
1/2✓ Branch 0 taken 260 times.
✗ Branch 1 not taken.
|
260 | keyuse->table_ref == tab->table_ref) |
| 2548 | 260 | keyuse++; | |
| 2549 | |||
| 2550 |
2/4✓ Branch 0 taken 284 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 284 times.
|
284 | if (create_ref_for_key(join, tab, keyuse, tab->prefix_tables())) { |
| 2551 | ✗ | can_skip_sorting = false; | |
| 2552 | ✗ | goto fix_ICP; | |
| 2553 | } | ||
| 2554 | |||
| 2555 |
2/4✓ Branch 0 taken 284 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 284 times.
✗ Branch 3 not taken.
|
284 | assert(tab->type() != JT_REF_OR_NULL && tab->type() != JT_FT); |
| 2556 | |||
| 2557 | // Changing the key makes filter_effect obsolete | ||
| 2558 | 284 | tab->position()->filter_effect = COND_FILTER_STALE; | |
| 2559 | |||
| 2560 | /* | ||
| 2561 | Check if it is possible to shift from ref to range. The index chosen | ||
| 2562 | for 'ref' has changed since the last time this function was called. | ||
| 2563 | */ | ||
| 2564 |
3/4✓ Branch 0 taken 284 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 260 times.
|
284 | if (can_switch_from_ref_to_range(thd, tab, order.order->direction, |
| 2565 | true)) { | ||
| 2566 | // Allow the code to fall-through to the next if condition. | ||
| 2567 | 24 | set_up_ref_access_to_key = false; | |
| 2568 | 24 | best_key = changed_key; | |
| 2569 | } | ||
| 2570 | } | ||
| 2571 |
4/4✓ Branch 0 taken 22288 times.
✓ Branch 1 taken 260 times.
✓ Branch 2 taken 12936 times.
✓ Branch 3 taken 9352 times.
|
22548 | if (!set_up_ref_access_to_key && best_key >= 0) { |
| 2572 | // Cancel any ref-access previously set up | ||
| 2573 | 12936 | tab->ref().key = -1; | |
| 2574 | 12936 | tab->ref().key_parts = 0; | |
| 2575 | |||
| 2576 | /* | ||
| 2577 | If ref_key used index tree reading only ('Using index' in EXPLAIN), | ||
| 2578 | and best_key doesn't, then revert the decision. | ||
| 2579 | */ | ||
| 2580 |
3/4✓ Branch 0 taken 12864 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 12864 times.
✗ Branch 3 not taken.
|
12936 | if (!table->covering_keys.is_set(best_key)) table->set_keyread(false); |
| 2581 | // Create an index scan if the table is not a temporary table that uses | ||
| 2582 | // Temptable engine (Does not support index_first() and index_last()) and | ||
| 2583 | // if there was no new range scan created. | ||
| 2584 | 12936 | if (!(is_temporary_table(tab->table_ref) && | |
| 2585 |
8/10✓ Branch 0 taken 79 times.
✓ Branch 1 taken 12857 times.
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 79 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 188 times.
✓ Branch 7 taken 12748 times.
✓ Branch 8 taken 12834 times.
✓ Branch 9 taken 102 times.
|
26060 | tab->table_ref->table->s->db_type() == temptable_hton) && |
| 2586 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 102 times.
|
13124 | ((!tab->range_scan() || tab->range_scan() == save_range_scan))) { |
| 2587 | // Avoid memory leak: | ||
| 2588 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 12834 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
12834 | assert(tab->range_scan() == save_range_scan || |
| 2589 | tab->range_scan() == nullptr); | ||
| 2590 | 12834 | tab->set_range_scan(nullptr); | |
| 2591 | 12834 | tab->set_index(best_key); | |
| 2592 | 12834 | tab->set_type(JT_INDEX_SCAN); // Read with index_first(), index_next() | |
| 2593 | /* | ||
| 2594 | There is a bug. When we change here, e.g. from group_min_max to | ||
| 2595 | index scan: loose index scan expected to read a small number of rows | ||
| 2596 | (jumping through the index), this small number was in | ||
| 2597 | position()->rows_fetched; index scan will read much more, so | ||
| 2598 | rows_fetched should be updated. So should the filtering effect. | ||
| 2599 | It is visible in main.distinct in trunk: | ||
| 2600 | explain SELECT distinct a from t3 order by a desc limit 2; | ||
| 2601 | id select_type table partitions type | ||
| 2602 | possible_keys key key_len ref rows filtered Extra 1 | ||
| 2603 | SIMPLE t3 NULL index a a 5 NULL | ||
| 2604 | 40 25.00 Using index "rows=40" should be ~200 i.e. # of records | ||
| 2605 | in table. Filter should be 100.00 (no WHERE). | ||
| 2606 | */ | ||
| 2607 |
1/2✓ Branch 0 taken 12834 times.
✗ Branch 1 not taken.
|
12834 | table->file->ha_index_or_rnd_end(); |
| 2608 | 12834 | tab->position()->filter_effect = COND_FILTER_STALE; | |
| 2609 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | } else if (tab->type() != JT_ALL) { |
| 2610 | /* | ||
| 2611 | We're about to use a quick access to the table. | ||
| 2612 | We need to change the access method so as the quick access | ||
| 2613 | method is actually used. | ||
| 2614 | */ | ||
| 2615 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
|
102 | assert(tab->range_scan()); |
| 2616 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
|
102 | assert(used_index(tab->range_scan()) == (uint)best_key); |
| 2617 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | tab->set_type(calc_join_type(tab->range_scan())); |
| 2618 | 102 | tab->use_quick = QS_RANGE; | |
| 2619 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
|
102 | if (is_loose_index_scan(tab->range_scan())) |
| 2620 | ✗ | join->tmp_table_param.precomputed_group_by = true; | |
| 2621 | 102 | tab->position()->filter_effect = COND_FILTER_STALE; | |
| 2622 | } | ||
| 2623 | } // best_key >= 0 | ||
| 2624 | |||
| 2625 |
2/2✓ Branch 0 taken 4126 times.
✓ Branch 1 taken 18422 times.
|
22548 | if (order_direction == -1) // If ORDER BY ... DESC |
| 2626 | { | ||
| 2627 |
2/2✓ Branch 0 taken 1603 times.
✓ Branch 1 taken 2523 times.
|
4126 | if (tab->range_scan()) { |
| 2628 | /* ORDER BY range_key DESC */ | ||
| 2629 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1603 times.
|
1603 | if (make_reverse(used_key_parts, tab->range_scan())) { |
| 2630 | /* purecov: begin inspected */ | ||
| 2631 | ✗ | can_skip_sorting = false; // Reverse sort failed -> filesort | |
| 2632 | ✗ | goto fix_ICP; | |
| 2633 | /* purecov: end */ | ||
| 2634 | } | ||
| 2635 |
1/2✓ Branch 0 taken 1603 times.
✗ Branch 1 not taken.
|
1603 | tab->set_type(calc_join_type(tab->range_scan())); |
| 2636 | 1603 | tab->position()->filter_effect = COND_FILTER_STALE; | |
| 2637 |
4/4✓ Branch 0 taken 854 times.
✓ Branch 1 taken 1669 times.
✓ Branch 2 taken 854 times.
✓ Branch 3 taken 1669 times.
|
3377 | } else if (tab->type() == JT_REF && |
| 2638 |
1/2✓ Branch 0 taken 854 times.
✗ Branch 1 not taken.
|
854 | tab->ref().key_parts <= used_key_parts) { |
| 2639 | /* | ||
| 2640 | SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC | ||
| 2641 | |||
| 2642 | Use a traversal function that starts by reading the last row | ||
| 2643 | with key part (A) and then traverse the index backwards. | ||
| 2644 | */ | ||
| 2645 | 854 | tab->reversed_access = true; | |
| 2646 | |||
| 2647 | /* | ||
| 2648 | The current implementation of the reverse RefIterator does not | ||
| 2649 | work well in combination with ICP and can lead to increased | ||
| 2650 | execution time. Setting changed_key to the current key | ||
| 2651 | (based on that we change the access order for the key) will | ||
| 2652 | ensure that a pushed index condition will be cancelled. | ||
| 2653 | */ | ||
| 2654 | 854 | changed_key = tab->ref().key; | |
| 2655 |
1/2✓ Branch 0 taken 1669 times.
✗ Branch 1 not taken.
|
1669 | } else if (tab->type() == JT_INDEX_SCAN) |
| 2656 | 1669 | tab->reversed_access = true; | |
| 2657 |
2/2✓ Branch 0 taken 3994 times.
✓ Branch 1 taken 14428 times.
|
18422 | } else if (tab->range_scan()) |
| 2658 | 3994 | set_need_sorted_output(tab->range_scan()); | |
| 2659 | |||
| 2660 | } // QEP has been modified | ||
| 2661 | |||
| 2662 | 102 | fix_ICP: | |
| 2663 | /* | ||
| 2664 | Cleanup: | ||
| 2665 | We may have both a 'tab->range_scan()' and 'save_range_scan' (original) | ||
| 2666 | at this point. Delete the one that we won't use. | ||
| 2667 | */ | ||
| 2668 |
4/4✓ Branch 0 taken 22650 times.
✓ Branch 1 taken 34159 times.
✓ Branch 2 taken 22548 times.
✓ Branch 3 taken 102 times.
|
56809 | if (can_skip_sorting && !no_changes) { |
| 2669 |
4/4✓ Branch 0 taken 15188 times.
✓ Branch 1 taken 7360 times.
✓ Branch 2 taken 3387 times.
✓ Branch 3 taken 19161 times.
|
37736 | if (tab->type() == JT_INDEX_SCAN && |
| 2670 |
2/2✓ Branch 0 taken 3387 times.
✓ Branch 1 taken 11801 times.
|
15188 | select_limit < table->file->stats.records) { |
| 2671 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3387 times.
|
3387 | assert(select_limit > 0); |
| 2672 | 3387 | tab->position()->rows_fetched = select_limit; | |
| 2673 | 3387 | tab->position()->filter_effect = COND_FILTER_STALE_NO_CONST; | |
| 2674 | } | ||
| 2675 | |||
| 2676 | // Keep current (ordered) tab->range_scan() | ||
| 2677 |
2/2✓ Branch 0 taken 197 times.
✓ Branch 1 taken 22351 times.
|
22548 | if (save_range_scan != tab->range_scan()) destroy(save_range_scan); |
| 2678 | } else { | ||
| 2679 | // Restore original save_range_scan | ||
| 2680 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 34257 times.
|
34261 | if (tab->range_scan() != save_range_scan) { |
| 2681 | 4 | destroy(tab->range_scan()); | |
| 2682 | 4 | tab->set_range_scan(save_range_scan); | |
| 2683 | } | ||
| 2684 | } | ||
| 2685 | |||
| 2686 |
1/2✓ Branch 0 taken 56809 times.
✗ Branch 1 not taken.
|
56809 | trace_steps.end(); |
| 2687 |
1/2✓ Branch 0 taken 56809 times.
✗ Branch 1 not taken.
|
56809 | Opt_trace_object trace_change_index(trace, "index_order_summary"); |
| 2688 |
1/2✓ Branch 0 taken 56809 times.
✗ Branch 1 not taken.
|
56809 | trace_change_index.add_utf8_table(tab->table_ref) |
| 2689 |
1/2✓ Branch 0 taken 56809 times.
✗ Branch 1 not taken.
|
56809 | .add("index_provides_order", can_skip_sorting) |
| 2690 |
3/4✓ Branch 0 taken 38307 times.
✓ Branch 1 taken 18502 times.
✓ Branch 2 taken 56809 times.
✗ Branch 3 not taken.
|
95116 | .add_alnum("order_direction", |
| 2691 | order_direction == 1 | ||
| 2692 | ? "asc" | ||
| 2693 |
2/2✓ Branch 0 taken 4154 times.
✓ Branch 1 taken 34153 times.
|
38307 | : ((order_direction == -1) ? "desc" : "undefined")); |
| 2694 | |||
| 2695 |
2/2✓ Branch 0 taken 14083 times.
✓ Branch 1 taken 42726 times.
|
56809 | if (changed_key >= 0) { |
| 2696 | // switching to another index | ||
| 2697 | // Should be no pushed index conditions at this point | ||
| 2698 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14083 times.
|
14083 | assert(!table->file->pushed_idx_cond); |
| 2699 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 14043 times.
|
14083 | if (unlikely(trace->is_started())) { |
| 2700 |
1/2✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
|
40 | trace_change_index.add_utf8("index", table->key_info[changed_key].name); |
| 2701 |
1/2✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
|
40 | trace_change_index.add("plan_changed", !no_changes); |
| 2702 |
1/2✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
|
40 | if (!no_changes) |
| 2703 |
1/2✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
|
40 | trace_change_index.add_alnum("access_type", join_type_str[tab->type()]); |
| 2704 | } | ||
| 2705 |
2/2✓ Branch 0 taken 81 times.
✓ Branch 1 taken 42645 times.
|
42726 | } else if (unlikely(trace->is_started())) { |
| 2706 |
2/4✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
|
162 | trace_change_index.add_utf8( |
| 2707 | 81 | "index", ref_key >= 0 ? table->key_info[ref_key].name : "unknown"); | |
| 2708 |
1/2✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
|
81 | trace_change_index.add("plan_changed", false); |
| 2709 | } | ||
| 2710 |
2/2✓ Branch 0 taken 43841 times.
✓ Branch 1 taken 12968 times.
|
56809 | *order_idx = best_key < 0 ? ref_key : best_key; |
| 2711 | 56809 | return can_skip_sorting; | |
| 2712 | 367758 | } | |
| 2713 | |||
| 2714 | /** | ||
| 2715 | Prune partitions for all tables of a join (query block). | ||
| 2716 | |||
| 2717 | Requires that tables have been locked. | ||
| 2718 | |||
| 2719 | @returns false if success, true if error | ||
| 2720 | */ | ||
| 2721 | |||
| 2722 | 19627 | bool JOIN::prune_table_partitions() { | |
| 2723 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19627 times.
|
19627 | assert(query_block->partitioned_table_count); |
| 2724 | |||
| 2725 |
2/2✓ Branch 0 taken 20186 times.
✓ Branch 1 taken 19624 times.
|
39810 | for (TABLE_LIST *tbl = query_block->leaf_tables; tbl; tbl = tbl->next_leaf) { |
| 2726 | // This will try to prune non-static conditions, which can be probed after | ||
| 2727 | // the tables are locked. | ||
| 2728 | |||
| 2729 | // Predicates for pruning of this table must be placed in the outer-most | ||
| 2730 | // join nest (Predicates in other join nests, or in the WHERE clause, | ||
| 2731 | // would have caused an outer join to be converted to an inner join, | ||
| 2732 | // and thus there would be no join nest graph to traverse) | ||
| 2733 | // Look up the join nest hierarchy for the outermost condition: | ||
| 2734 | 20186 | Item *cond = where_cond; | |
| 2735 | 20186 | const table_map tbl_map = tbl->map(); | |
| 2736 |
2/2✓ Branch 0 taken 20413 times.
✓ Branch 1 taken 20166 times.
|
40579 | for (TABLE_LIST *nest = tbl; nest != nullptr; nest = nest->embedding) { |
| 2737 |
6/6✓ Branch 0 taken 310 times.
✓ Branch 1 taken 20103 times.
✓ Branch 2 taken 265 times.
✓ Branch 3 taken 45 times.
✓ Branch 4 taken 265 times.
✓ Branch 5 taken 20148 times.
|
20723 | if (nest->join_cond_optim() != nullptr && |
| 2738 | 310 | Overlaps(tbl_map, nest->join_cond_optim()->used_tables())) { | |
| 2739 | 265 | cond = nest->join_cond_optim(); | |
| 2740 | // For an anti-join operation, a synthetic left join nest is added above | ||
| 2741 | // the anti-join nest. Make sure that we skip this when searching for | ||
| 2742 | // the predicate to prune. | ||
| 2743 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 245 times.
|
265 | if (nest->is_aj_nest()) break; |
| 2744 | } | ||
| 2745 | } | ||
| 2746 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 20183 times.
|
20186 | if (prune_partitions(thd, tbl->table, query_block, cond)) { |
| 2747 | 3 | return true; | |
| 2748 | } | ||
| 2749 | } | ||
| 2750 | |||
| 2751 | 19624 | return false; | |
| 2752 | } | ||
| 2753 | |||
| 2754 | /** | ||
| 2755 | A helper function to check whether it's better to use range than ref. | ||
| 2756 | |||
| 2757 | @details | ||
| 2758 | Heuristic: Switch from 'ref' to 'range' access if 'range' | ||
| 2759 | access can utilize more keyparts than 'ref' access. Conditions | ||
| 2760 | for doing switching: | ||
| 2761 | |||
| 2762 | 1) Range access is possible | ||
| 2763 | 2) 'ref' access and 'range' access uses the same index | ||
| 2764 | 3) Used parts of key shouldn't have nullable parts & ref_or_null isn't used. | ||
| 2765 | 4) 'ref' access depends on a constant, not a value read from a | ||
| 2766 | table earlier in the join sequence. | ||
| 2767 | |||
| 2768 | Rationale: if 'ref' depends on a value from another table, | ||
| 2769 | the join condition is not used to limit the rows read by | ||
| 2770 | 'range' access (that would require dynamic range - 'Range | ||
| 2771 | checked for each record'). In other words, if 'ref' depends | ||
| 2772 | on a value from another table, we have a query with | ||
| 2773 | conditions of the form | ||
| 2774 | |||
| 2775 | this_table.idx_col1 = other_table.col AND <<- used by 'ref' | ||
| 2776 | this_table.idx_col1 OP @<const@> AND <<- used by 'range' | ||
| 2777 | this_table.idx_col2 OP @<const@> AND ... <<- used by 'range' | ||
| 2778 | |||
| 2779 | and an index on (idx_col1,idx_col2,...). But the fact that | ||
| 2780 | 'range' access uses more keyparts does not mean that it is | ||
| 2781 | more selective than 'ref' access because these access types | ||
| 2782 | utilize different parts of the query condition. We | ||
| 2783 | therefore trust the cost based choice made by | ||
| 2784 | best_access_path() instead of forcing a heuristic choice | ||
| 2785 | here. | ||
| 2786 | 5) 'range' access uses more keyparts than 'ref' access | ||
| 2787 | 6) ORDER BY might make range better than table scan: | ||
| 2788 | Check possibility of range scan even if it was previously deemed unviable | ||
| 2789 | (for example when table scan was estimated to be cheaper). If yes, | ||
| 2790 | range-access should be chosen only for larger key length. | ||
| 2791 | |||
| 2792 | @param thd To re-run range optimizer. | ||
| 2793 | @param tab JOIN_TAB to check | ||
| 2794 | @param ordering Used as a parameter to call test_quick_select. | ||
| 2795 | @param recheck_range Check possibility of range scan even if it is currently | ||
| 2796 | unviable. | ||
| 2797 | |||
| 2798 | @return true Range is better than ref | ||
| 2799 | @return false Ref is better or switch isn't possible | ||
| 2800 | |||
| 2801 | @todo: This decision should rather be made in best_access_path() | ||
| 2802 | */ | ||
| 2803 | |||
| 2804 | 2022958 | static bool can_switch_from_ref_to_range(THD *thd, JOIN_TAB *tab, | |
| 2805 | enum_order ordering, | ||
| 2806 | bool recheck_range) { | ||
| 2807 |
2/2✓ Branch 0 taken 4260 times.
✓ Branch 1 taken 213979 times.
|
2241197 | if ((tab->range_scan() && // 1) |
| 2808 |
6/6✓ Branch 0 taken 218239 times.
✓ Branch 1 taken 1804736 times.
✓ Branch 2 taken 284 times.
✓ Branch 3 taken 1808712 times.
✓ Branch 4 taken 214263 times.
✓ Branch 5 taken 1808712 times.
|
2241214 | tab->position()->key->key == used_index(tab->range_scan())) || // 2) |
| 2809 | recheck_range) { | ||
| 2810 | 214263 | uint keyparts = 0, length = 0; | |
| 2811 | 214263 | table_map dep_map = 0; | |
| 2812 | 214263 | bool maybe_null = false; | |
| 2813 | |||
| 2814 |
1/2✓ Branch 0 taken 214263 times.
✗ Branch 1 not taken.
|
428526 | calc_length_and_keyparts(tab->position()->key, tab, |
| 2815 | 214263 | tab->position()->key->key, tab->prefix_tables(), | |
| 2816 | nullptr, &length, &keyparts, &dep_map, | ||
| 2817 | &maybe_null); | ||
| 2818 |
2/2✓ Branch 0 taken 214172 times.
✓ Branch 1 taken 91 times.
|
214263 | if (!maybe_null && // 3) |
| 2819 |
2/2✓ Branch 0 taken 75896 times.
✓ Branch 1 taken 138276 times.
|
214172 | !dep_map) // 4) |
| 2820 | { | ||
| 2821 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 75859 times.
|
75896 | if (recheck_range) // 6) |
| 2822 | { | ||
| 2823 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | Key_map new_ref_key_map; |
| 2824 | 37 | new_ref_key_map.set_bit(tab->ref().key); | |
| 2825 | |||
| 2826 | 37 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 2827 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | Opt_trace_object trace_wrapper(trace); |
| 2828 | Opt_trace_object can_switch( | ||
| 2829 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | trace, "check_if_range_uses_more_keyparts_than_ref"); |
| 2830 | Opt_trace_object trace_cond( | ||
| 2831 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | trace, "rerunning_range_optimizer_for_single_index"); |
| 2832 | |||
| 2833 | AccessPath *range_scan; | ||
| 2834 | MEM_ROOT temp_mem_root(key_memory_test_quick_select_exec, | ||
| 2835 | 37 | thd->variables.range_alloc_block_size); | |
| 2836 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
|
148 | if (test_quick_select( |
| 2837 | thd, thd->mem_root, &temp_mem_root, new_ref_key_map, 0, | ||
| 2838 | 0, // empty table_map | ||
| 2839 | 37 | tab->join()->row_limit, false, ordering, tab->table(), | |
| 2840 | 37 | tab->skip_records_in_range(), | |
| 2841 | 37 | tab->join_cond() ? tab->join_cond() : tab->join()->where_cond, | |
| 2842 | 37 | &tab->needed_reg, recheck_range, tab->join()->query_block, | |
| 2843 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 6 times.
|
37 | &range_scan) > 0) { |
| 2844 |
3/4✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 7 times.
|
31 | if (length < get_max_used_key_length(range_scan)) { |
| 2845 | 24 | destroy(tab->range_scan()); | |
| 2846 | 24 | tab->set_range_scan(range_scan); | |
| 2847 | 24 | return true; | |
| 2848 | } | ||
| 2849 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
14 | Opt_trace_object(trace, "access_type_unchanged") |
| 2850 | 14 | .add("ref_key_length", length) | |
| 2851 |
3/6✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
7 | .add("range_key_length", get_max_used_key_length(range_scan)); |
| 2852 | 7 | destroy(range_scan); | |
| 2853 | } | ||
| 2854 |
8/8✓ Branch 0 taken 13 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 24 times.
|
109 | } else |
| 2855 |
1/2✓ Branch 0 taken 75859 times.
✗ Branch 1 not taken.
|
75859 | return length < get_max_used_key_length(tab->range_scan()); // 5) |
| 2856 | } | ||
| 2857 | } | ||
| 2858 | 1947092 | return false; | |
| 2859 | } | ||
| 2860 | |||
| 2861 | /** | ||
| 2862 | An utility function - apply heuristics and optimize access methods to tables. | ||
| 2863 | Currently this function can change REF to RANGE and ALL to INDEX scan if | ||
| 2864 | latter is considered to be better (not cost-based) than the former. | ||
| 2865 | @note Side effect - this function could set 'Impossible WHERE' zero | ||
| 2866 | result. | ||
| 2867 | */ | ||
| 2868 | |||
| 2869 | 1815625 | void JOIN::adjust_access_methods() { | |
| 2870 |
3/6✓ Branch 0 taken 1815629 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1815635 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1815640 times.
✗ Branch 5 not taken.
|
1815625 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 2871 |
2/2✓ Branch 0 taken 6295684 times.
✓ Branch 1 taken 1815654 times.
|
8111338 | for (uint i = const_tables; i < tables; i++) { |
| 2872 | 6295684 | JOIN_TAB *const tab = best_ref[i]; | |
| 2873 | 6295684 | TABLE_LIST *const tl = tab->table_ref; | |
| 2874 | |||
| 2875 |
2/2✓ Branch 0 taken 1774526 times.
✓ Branch 1 taken 4521171 times.
|
6295684 | if (tab->type() == JT_ALL) { |
| 2876 | /* | ||
| 2877 | It's possible to speedup query by switching from full table scan to | ||
| 2878 | the scan of covering index, due to less data being read. | ||
| 2879 | Prerequisites for this are: | ||
| 2880 | 1) Keyread (i.e index only scan) is allowed (table isn't updated/deleted | ||
| 2881 | from) | ||
| 2882 | 2) Covering indexes are available | ||
| 2883 | 3) This isn't a derived table/materialized view | ||
| 2884 | */ | ||
| 2885 | 1774526 | if (!tab->table()->no_keyread && // 1 | |
| 2886 |
6/6✓ Branch 0 taken 1716052 times.
✓ Branch 1 taken 58483 times.
✓ Branch 2 taken 383949 times.
✓ Branch 3 taken 1332111 times.
✓ Branch 4 taken 383849 times.
✓ Branch 5 taken 1390691 times.
|
2158481 | !tab->table()->covering_keys.is_clear_all() && // 2 |
| 2887 |
2/2✓ Branch 0 taken 383850 times.
✓ Branch 1 taken 96 times.
|
383949 | !tl->uses_materialization()) // 3 |
| 2888 | { | ||
| 2889 | /* | ||
| 2890 | It has turned out that the change commented out below, while speeding | ||
| 2891 | things up for disk-bound loads, slows them down for cases when the data | ||
| 2892 | is in disk cache (see BUG#35850): | ||
| 2893 | // See bug #26447: "Using the clustered index for a table scan | ||
| 2894 | // is always faster than using a secondary index". | ||
| 2895 | if (table->s->primary_key != MAX_KEY && | ||
| 2896 | table->file->primary_key_is_clustered()) | ||
| 2897 | tab->index= table->s->primary_key; | ||
| 2898 | else | ||
| 2899 | tab->index=find_shortest_key(table, & table->covering_keys); | ||
| 2900 | */ | ||
| 2901 |
2/2✓ Branch 0 taken 383797 times.
✓ Branch 1 taken 51 times.
|
383849 | if (tab->position()->sj_strategy != SJ_OPT_LOOSE_SCAN) |
| 2902 | 383796 | tab->set_index( | |
| 2903 | 383797 | find_shortest_key(tab->table(), &tab->table()->covering_keys)); | |
| 2904 | 383849 | tab->set_type(JT_INDEX_SCAN); // Read with index_first / index_next | |
| 2905 | // From table scan to index scan, thus filter effect needs no recalc. | ||
| 2906 |
6/6✓ Branch 0 taken 1332206 times.
✓ Branch 1 taken 58486 times.
✓ Branch 2 taken 1190170 times.
✓ Branch 3 taken 142033 times.
✓ Branch 4 taken 1190168 times.
✓ Branch 5 taken 200521 times.
|
1390691 | } else if (!tab->table()->no_keyread && !tl->uses_materialization()) { |
| 2907 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1190173 times.
|
1190168 | assert(tab->table()->covering_keys.is_clear_all()); |
| 2908 |
1/2✓ Branch 0 taken 1190173 times.
✗ Branch 1 not taken.
|
1190173 | if (tab->position()->sj_strategy != SJ_OPT_LOOSE_SCAN) { |
| 2909 |
1/2✓ Branch 0 taken 1190173 times.
✗ Branch 1 not taken.
|
1190173 | Key_map clustering_keys; |
| 2910 |
2/2✓ Branch 0 taken 1507533 times.
✓ Branch 1 taken 1190170 times.
|
2697706 | for (uint i2 = 0; i2 < tab->table()->s->keys; i2++) { |
| 2911 |
3/4✓ Branch 0 taken 614208 times.
✓ Branch 1 taken 893324 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1507532 times.
|
2121741 | if (tab->keys().is_set(i2) && |
| 2912 |
2/4✓ Branch 0 taken 614208 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 614208 times.
|
614208 | tab->table()->file->index_flags(i2, 0, 0) & HA_CLUSTERED_INDEX) |
| 2913 | ✗ | clustering_keys.set_bit(i2); | |
| 2914 | } | ||
| 2915 |
1/2✓ Branch 0 taken 1190169 times.
✗ Branch 1 not taken.
|
1190170 | uint index = find_shortest_key(tab->table(), &clustering_keys); |
| 2916 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1190169 times.
|
1190169 | if (index != MAX_KEY) { |
| 2917 | ✗ | tab->set_type(JT_INDEX_SCAN); | |
| 2918 | ✗ | tab->set_index(index); | |
| 2919 | } | ||
| 2920 | } | ||
| 2921 | } | ||
| 2922 |
2/2✓ Branch 0 taken 2022690 times.
✓ Branch 1 taken 2498486 times.
|
4521171 | } else if (tab->type() == JT_REF) { |
| 2923 |
2/2✓ Branch 0 taken 1017 times.
✓ Branch 1 taken 2021657 times.
|
2022690 | if (can_switch_from_ref_to_range(thd, tab, ORDER_NOT_RELEVANT, false)) { |
| 2924 | 1017 | tab->set_type(JT_RANGE); | |
| 2925 | |||
| 2926 | 1017 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 2927 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
1017 | Opt_trace_object wrapper(trace); |
| 2928 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
2034 | Opt_trace_object(trace, "access_type_changed") |
| 2929 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
1017 | .add_utf8_table(tl) |
| 2930 | 2034 | .add_utf8("index", | |
| 2931 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
1017 | tab->table()->key_info[tab->position()->key->key].name) |
| 2932 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
1017 | .add_alnum("old_type", "ref") |
| 2933 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
1017 | .add_alnum("new_type", join_type_str[tab->type()]) |
| 2934 |
1/2✓ Branch 0 taken 1017 times.
✗ Branch 1 not taken.
|
1017 | .add_alnum("cause", "uses_more_keyparts"); |
| 2935 | |||
| 2936 | 1017 | tab->use_quick = QS_RANGE; | |
| 2937 | 1017 | tab->position()->filter_effect = COND_FILTER_STALE; | |
| 2938 | 1017 | } else { | |
| 2939 | // Cleanup quick, REF/REF_OR_NULL/EQ_REF, will be clarified later | ||
| 2940 | 2021657 | ::destroy(tab->range_scan()); | |
| 2941 | 2021657 | tab->set_range_scan(nullptr); | |
| 2942 | } | ||
| 2943 | } | ||
| 2944 | // Ensure AM consistency | ||
| 2945 |
4/6✓ Branch 0 taken 32149 times.
✓ Branch 1 taken 6263554 times.
✓ Branch 2 taken 32149 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 32149 times.
✗ Branch 5 not taken.
|
6295711 | assert(!(tab->range_scan() && |
| 2946 | (tab->type() == JT_REF || tab->type() == JT_ALL))); | ||
| 2947 |
5/6✓ Branch 0 taken 6264690 times.
✓ Branch 1 taken 31026 times.
✓ Branch 2 taken 6263570 times.
✓ Branch 3 taken 1122 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 32149 times.
|
6295703 | assert((tab->type() != JT_RANGE && tab->type() != JT_INDEX_MERGE) || |
| 2948 | tab->range_scan()); | ||
| 2949 | 6295719 | if (!tab->const_keys.is_clear_all() && | |
| 2950 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 533987 times.
|
533997 | tab->table()->reginfo.impossible_range && |
| 2951 |
5/6✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 4 times.
|
20 | ((i == const_tables && tab->type() == JT_REF) || |
| 2952 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
22 | ((tab->type() == JT_ALL || tab->type() == JT_RANGE || |
| 2953 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
12 | tab->type() == JT_INDEX_MERGE || tab->type() == JT_INDEX_SCAN) && |
| 2954 |
5/6✓ Branch 0 taken 533997 times.
✓ Branch 1 taken 5761725 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 6295698 times.
|
6829723 | tab->use_quick != QS_RANGE)) && |
| 2955 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
24 | !tab->table_ref->is_inner_table_of_outer_join()) |
| 2956 | 4 | zero_result_cause = "Impossible WHERE noticed after reading const tables"; | |
| 2957 | } | ||
| 2958 | 1815654 | } | |
| 2959 | |||
| 2960 | 3824086 | static JOIN_TAB *alloc_jtab_array(THD *thd, uint table_count) { | |
| 2961 |
5/8✓ Branch 0 taken 3824095 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3824114 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6499285 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6499280 times.
✓ Branch 7 taken 3824119 times.
|
10323366 | JOIN_TAB *t = new (thd->mem_root) JOIN_TAB[table_count]; |
| 2962 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3824119 times.
|
3824119 | if (!t) return nullptr; /* purecov: inspected */ |
| 2963 | |||
| 2964 |
5/8✓ Branch 0 taken 3824121 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3824121 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6499241 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6499258 times.
✓ Branch 7 taken 3824104 times.
|
10323360 | QEP_shared *qs = new (thd->mem_root) QEP_shared[table_count]; |
| 2965 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3824104 times.
|
3824104 | if (!qs) return nullptr; /* purecov: inspected */ |
| 2966 | |||
| 2967 |
2/2✓ Branch 0 taken 6499275 times.
✓ Branch 1 taken 3824101 times.
|
10323375 | for (uint i = 0; i < table_count; ++i) t[i].set_qs(qs++); |
| 2968 | |||
| 2969 | 3824101 | return t; | |
| 2970 | } | ||
| 2971 | |||
| 2972 | /** | ||
| 2973 | Set up JOIN_TAB structs according to the picked join order in best_positions. | ||
| 2974 | This allocates execution structures so may be called only after we have the | ||
| 2975 | very final plan. It must be called after | ||
| 2976 | Optimize_table_order::fix_semijoin_strategies(). | ||
| 2977 | |||
| 2978 | @return False if success, True if error | ||
| 2979 | |||
| 2980 | @details | ||
| 2981 | - create join->join_tab array and copy from existing JOIN_TABs in join order | ||
| 2982 | - create helper structs for materialized semi-join handling | ||
| 2983 | - finalize semi-join strategy choices | ||
| 2984 | - Number of intermediate tables "tmp_tables" is calculated. | ||
| 2985 | - "tables" and "primary_tables" are recalculated. | ||
| 2986 | - for full and index scans info of estimated # of records is updated. | ||
| 2987 | - in a helper function: | ||
| 2988 | - all heuristics are applied and the final access method type is picked | ||
| 2989 | for each join_tab (only test_if_skip_sortorder() could override it) | ||
| 2990 | - AM consistency is ensured (e.g only range and index merge are allowed | ||
| 2991 | to have quick select set). | ||
| 2992 | - if "Impossible WHERE" is detected - appropriate zero_result_cause is | ||
| 2993 | set. | ||
| 2994 | |||
| 2995 | Notice that intermediate tables will not have a POSITION reference; and they | ||
| 2996 | will not have a TABLE reference before the final stages of code generation. | ||
| 2997 | |||
| 2998 | @todo the block which sets tab->type should move to adjust_access_methods | ||
| 2999 | for unification. | ||
| 3000 | */ | ||
| 3001 | |||
| 3002 | 1911974 | bool JOIN::get_best_combination() { | |
| 3003 |
1/2✓ Branch 0 taken 1911999 times.
✗ Branch 1 not taken.
|
1911974 | DBUG_TRACE; |
| 3004 | |||
| 3005 | // At this point "tables" and "primary"tables" represent the same: | ||
| 3006 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1911999 times.
|
1911999 | assert(tables == primary_tables); |
| 3007 | |||
| 3008 | /* | ||
| 3009 | Allocate additional space for tmp tables. | ||
| 3010 | Number of plan nodes: | ||
| 3011 | # of regular input tables (including semi-joined ones) + | ||
| 3012 | # of semi-join nests for materialization + | ||
| 3013 | 1? + // For GROUP BY (or implicit grouping when we have windowing) | ||
| 3014 | 1? + // For DISTINCT | ||
| 3015 | 1? + // For aggregation functions aggregated in outer query | ||
| 3016 | // when used with distinct | ||
| 3017 | 1? + // For ORDER BY | ||
| 3018 | 1? // buffer result | ||
| 3019 | |||
| 3020 | Up to 2 tmp tables + N window output tmp are allocated (NOTE: windows also | ||
| 3021 | have frame buffer tmp tables, but those are not relevant here). | ||
| 3022 | */ | ||
| 3023 | uint num_tmp_tables = | ||
| 3024 |
4/4✓ Branch 0 taken 420548 times.
✓ Branch 1 taken 1480994 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 420530 times.
|
3813541 | (!group_list.empty() || (implicit_grouping && m_windows.elements > 0) |
| 3025 |
2/2✓ Branch 0 taken 1901542 times.
✓ Branch 1 taken 10443 times.
|
3813527 | ? 1 |
| 3026 | 1911985 | : 0) + | |
| 3027 |
4/4✓ Branch 0 taken 4012 times.
✓ Branch 1 taken 1907973 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 3975 times.
|
1911985 | (select_distinct ? (tmp_table_param.outer_sum_func_count ? 2 : 1) : 0) + |
| 3028 |
2/2✓ Branch 0 taken 1272970 times.
✓ Branch 1 taken 639020 times.
|
1911985 | (order.empty() ? 0 : 1) + |
| 3029 | 1911990 | (query_block->active_options() & | |
| 3030 | (SELECT_BIG_RESULT | OPTION_BUFFER_RESULT) | ||
| 3031 |
2/2✓ Branch 0 taken 7203 times.
✓ Branch 1 taken 1904788 times.
|
1911991 | ? 1 |
| 3032 | 1911991 | : 0) + | |
| 3033 | 1911991 | m_windows.elements + 1; /* the presence of windows may increase need for | |
| 3034 | grouping tmp tables, cf. de-optimization | ||
| 3035 | in make_tmp_tables_info | ||
| 3036 | */ | ||
| 3037 |
2/2✓ Branch 0 taken 4669 times.
✓ Branch 1 taken 1907322 times.
|
1911991 | if (num_tmp_tables > (2 + m_windows.elements)) |
| 3038 | 4669 | num_tmp_tables = 2 + m_windows.elements; | |
| 3039 | |||
| 3040 | /* | ||
| 3041 | Rearrange queries with materialized semi-join nests so that the semi-join | ||
| 3042 | nest is replaced with a reference to a materialized temporary table and all | ||
| 3043 | materialized subquery tables are placed after the intermediate tables. | ||
| 3044 | After the following loop, "inner_target" is the position of the first | ||
| 3045 | subquery table (if any). "outer_target" is the position of first outer | ||
| 3046 | table, and will later be used to track the position of any materialized | ||
| 3047 | temporary tables. | ||
| 3048 | */ | ||
| 3049 |
1/2✓ Branch 0 taken 1911997 times.
✗ Branch 1 not taken.
|
1911991 | const bool has_semijoin = !query_block->sj_nests.empty(); |
| 3050 | 1911997 | uint outer_target = 0; | |
| 3051 | 1911997 | uint inner_target = primary_tables + num_tmp_tables; | |
| 3052 | 1911997 | uint sjm_nests = 0; | |
| 3053 | |||
| 3054 |
2/2✓ Branch 0 taken 2721 times.
✓ Branch 1 taken 1909276 times.
|
1911997 | if (has_semijoin) { |
| 3055 |
2/2✓ Branch 0 taken 14354 times.
✓ Branch 1 taken 2721 times.
|
17075 | for (uint tableno = 0; tableno < primary_tables;) { |
| 3056 |
2/2✓ Branch 0 taken 934 times.
✓ Branch 1 taken 13420 times.
|
14354 | if (sj_is_materialize_strategy(best_positions[tableno].sj_strategy)) { |
| 3057 | 934 | sjm_nests++; | |
| 3058 | 934 | inner_target -= (best_positions[tableno].n_sj_tables - 1); | |
| 3059 | 934 | tableno += best_positions[tableno].n_sj_tables; | |
| 3060 | } else | ||
| 3061 | 13420 | tableno++; | |
| 3062 | } | ||
| 3063 | } | ||
| 3064 | |||
| 3065 | 1911997 | JOIN_TAB *tmp_join_tabs = nullptr; | |
| 3066 |
2/2✓ Branch 0 taken 1911985 times.
✓ Branch 1 taken 12 times.
|
1911997 | if (sjm_nests + num_tmp_tables) { |
| 3067 | // join_tab array only has "primary_tables" tables. We need those more: | ||
| 3068 |
2/4✓ Branch 0 taken 1911996 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1911996 times.
|
1911985 | if (!(tmp_join_tabs = alloc_jtab_array(thd, sjm_nests + num_tmp_tables))) |
| 3069 | ✗ | return true; /* purecov: inspected */ | |
| 3070 | } | ||
| 3071 | |||
| 3072 | // To check that we fill the array correctly: fill it with zeros first | ||
| 3073 | 1912008 | memset(best_ref, 0, | |
| 3074 | 1912008 | sizeof(JOIN_TAB *) * (primary_tables + sjm_nests + num_tmp_tables)); | |
| 3075 | |||
| 3076 | 1912008 | int sjm_index = tables; // Number assigned to materialized temporary table | |
| 3077 | 1912008 | int remaining_sjm_inner = 0; | |
| 3078 | 1912008 | bool err = false; | |
| 3079 |
2/2✓ Branch 0 taken 3928386 times.
✓ Branch 1 taken 1912021 times.
|
5840407 | for (uint tableno = 0; tableno < tables; tableno++) { |
| 3080 | 3928386 | POSITION *const pos = best_positions + tableno; | |
| 3081 |
6/6✓ Branch 0 taken 15794 times.
✓ Branch 1 taken 3912592 times.
✓ Branch 2 taken 934 times.
✓ Branch 3 taken 14860 times.
✓ Branch 4 taken 934 times.
✓ Branch 5 taken 3927452 times.
|
3928386 | if (has_semijoin && sj_is_materialize_strategy(pos->sj_strategy)) { |
| 3082 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 934 times.
|
934 | assert(outer_target < inner_target); |
| 3083 | |||
| 3084 | 934 | TABLE_LIST *const sj_nest = pos->table->emb_sj_nest; | |
| 3085 | |||
| 3086 | // Handle this many inner tables of materialized semi-join | ||
| 3087 | 934 | remaining_sjm_inner = pos->n_sj_tables; | |
| 3088 | |||
| 3089 | /* | ||
| 3090 | If we fail in some allocation below, we cannot bail out immediately; | ||
| 3091 | that would put us in a difficult situation to clean up; imagine we | ||
| 3092 | have planned this layout: | ||
| 3093 | outer1 - sj_mat_tmp1 - outer2 - sj_mat_tmp2 - outer3 | ||
| 3094 | We have successfully filled a JOIN_TAB for sj_mat_tmp1, and are | ||
| 3095 | failing to fill a JOIN_TAB for sj_mat_tmp2 (OOM). So we want to quit | ||
| 3096 | this function, which will lead to cleanup functions. | ||
| 3097 | But sj_mat_tmp1 is in this->best_ref only, outer3 is in this->join_tab | ||
| 3098 | only: what is the array to traverse for cleaning up? What is the | ||
| 3099 | number of tables to loop over? | ||
| 3100 | So: if we fail in the present loop, we record the error but continue | ||
| 3101 | filling best_ref; when it's fully filled, bail out, because then | ||
| 3102 | best_ref can be used as reliable array for cleaning up. | ||
| 3103 | */ | ||
| 3104 | 934 | JOIN_TAB *const tab = tmp_join_tabs++; | |
| 3105 | 934 | best_ref[outer_target] = tab; | |
| 3106 | 934 | tab->set_join(this); | |
| 3107 | 934 | tab->set_idx(outer_target); | |
| 3108 | |||
| 3109 | /* | ||
| 3110 | Up to this point there cannot be a failure. JOIN_TAB has been filled | ||
| 3111 | enough to be clean-able. | ||
| 3112 | */ | ||
| 3113 | |||
| 3114 | 934 | Semijoin_mat_exec *const sjm_exec = new (thd->mem_root) Semijoin_mat_exec( | |
| 3115 | 934 | sj_nest, (pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN), | |
| 3116 |
2/4✓ Branch 0 taken 934 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 934 times.
✗ Branch 3 not taken.
|
934 | remaining_sjm_inner, outer_target, inner_target); |
| 3117 | |||
| 3118 | 934 | tab->set_sj_mat_exec(sjm_exec); | |
| 3119 | |||
| 3120 |
3/6✓ Branch 0 taken 934 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 934 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 934 times.
|
1868 | if (!sjm_exec || setup_semijoin_materialized_table( |
| 3121 |
1/2✓ Branch 0 taken 934 times.
✗ Branch 1 not taken.
|
934 | tab, sjm_index, pos, best_positions + sjm_index)) |
| 3122 | ✗ | err = true; /* purecov: inspected */ | |
| 3123 | |||
| 3124 | 934 | outer_target++; | |
| 3125 | 934 | sjm_index++; | |
| 3126 | } | ||
| 3127 | /* | ||
| 3128 | Locate join_tab target for the table we are considering. | ||
| 3129 | (remaining_sjm_inner becomes negative for non-SJM tables, this can be | ||
| 3130 | safely ignored). | ||
| 3131 | */ | ||
| 3132 | const uint target = | ||
| 3133 |
2/2✓ Branch 0 taken 2374 times.
✓ Branch 1 taken 3926012 times.
|
3928386 | (remaining_sjm_inner--) > 0 ? inner_target++ : outer_target++; |
| 3134 | 3928386 | JOIN_TAB *const tab = pos->table; | |
| 3135 | |||
| 3136 | 3928386 | best_ref[target] = tab; | |
| 3137 | 3928386 | tab->set_idx(target); | |
| 3138 | 3928383 | tab->set_position(pos); | |
| 3139 | 3928395 | TABLE *const table = tab->table(); | |
| 3140 |
6/6✓ Branch 0 taken 3841996 times.
✓ Branch 1 taken 86409 times.
✓ Branch 2 taken 3827436 times.
✓ Branch 3 taken 14560 times.
✓ Branch 4 taken 3827435 times.
✓ Branch 5 taken 100970 times.
|
3928401 | if (tab->type() != JT_CONST && tab->type() != JT_SYSTEM) { |
| 3141 |
5/6✓ Branch 0 taken 63 times.
✓ Branch 1 taken 3827372 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 55 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3827435 times.
|
3827443 | if (pos->sj_strategy == SJ_OPT_LOOSE_SCAN && tab->range_scan() && |
| 3142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | used_index(tab->range_scan()) != pos->loosescan_key) { |
| 3143 | /* | ||
| 3144 | We must use the duplicate-eliminating index, so this QUICK is not | ||
| 3145 | an option. | ||
| 3146 | */ | ||
| 3147 | ✗ | ::destroy(tab->range_scan()); | |
| 3148 | ✗ | tab->set_range_scan(nullptr); | |
| 3149 | } | ||
| 3150 |
2/2✓ Branch 0 taken 1804853 times.
✓ Branch 1 taken 2022577 times.
|
3827430 | if (!pos->key) { |
| 3151 |
2/2✓ Branch 0 taken 31132 times.
✓ Branch 1 taken 1773719 times.
|
1804853 | if (tab->range_scan()) |
| 3152 |
1/2✓ Branch 0 taken 31132 times.
✗ Branch 1 not taken.
|
31132 | tab->set_type(calc_join_type(tab->range_scan())); |
| 3153 | else | ||
| 3154 | 1773719 | tab->set_type(JT_ALL); | |
| 3155 | } else | ||
| 3156 | // REF or RANGE, clarify later when prefix tables are set for JOIN_TABs | ||
| 3157 | 2022577 | tab->set_type(JT_REF); | |
| 3158 | } | ||
| 3159 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3928404 times.
|
3928395 | assert(tab->type() != JT_UNKNOWN); |
| 3160 | |||
| 3161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3928404 times.
|
3928404 | assert(table->reginfo.join_tab == tab); |
| 3162 |
2/2✓ Branch 0 taken 3526468 times.
✓ Branch 1 taken 401930 times.
|
3928404 | if (!tab->join_cond()) |
| 3163 | 3526468 | table->reginfo.not_exists_optimize = false; // Only with LEFT JOIN | |
| 3164 | 3928398 | map2table[tab->table_ref->tableno()] = tab; | |
| 3165 | } | ||
| 3166 | |||
| 3167 | // Count the materialized semi-join tables as regular input tables | ||
| 3168 | 1912021 | tables += sjm_nests + num_tmp_tables; | |
| 3169 | // Set the number of non-materialized tables: | ||
| 3170 | 1912021 | primary_tables = outer_target; | |
| 3171 | |||
| 3172 | /* | ||
| 3173 | Between the last outer table or sj-mat tmp table, and the first sj-mat | ||
| 3174 | inner table, there may be 2 slots for sort/group/etc tmp tables: | ||
| 3175 | */ | ||
| 3176 |
2/2✓ Branch 0 taken 2569761 times.
✓ Branch 1 taken 1912019 times.
|
4481780 | for (uint i = 0; i < num_tmp_tables; ++i) { |
| 3177 | 2569761 | const uint idx = outer_target + i; | |
| 3178 | 2569761 | tmp_join_tabs->set_join(this); | |
| 3179 | 2569760 | tmp_join_tabs->set_idx(idx); | |
| 3180 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2569759 times.
|
2569759 | assert(best_ref[idx] == nullptr); // verify that not overwriting |
| 3181 | 2569759 | best_ref[idx] = tmp_join_tabs++; | |
| 3182 | /* | ||
| 3183 | note that set_table() cannot be called yet. We may not even use this | ||
| 3184 | JOIN_TAB in the end, it's dummy at the moment. Which can be tested with | ||
| 3185 | "position()!=NULL". | ||
| 3186 | */ | ||
| 3187 | } | ||
| 3188 | |||
| 3189 | // make array unreachable: should walk JOIN_TABs by best_ref now | ||
| 3190 | 1912019 | join_tab = nullptr; | |
| 3191 | |||
| 3192 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1912019 times.
|
1912019 | if (err) return true; /* purecov: inspected */ |
| 3193 | |||
| 3194 |
2/2✓ Branch 0 taken 2721 times.
✓ Branch 1 taken 1909298 times.
|
1912019 | if (has_semijoin) { |
| 3195 |
1/2✓ Branch 0 taken 2721 times.
✗ Branch 1 not taken.
|
2721 | set_semijoin_info(); |
| 3196 | |||
| 3197 | // Update equalities and keyuses after having added SJ materialization | ||
| 3198 |
2/4✓ Branch 0 taken 2721 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2721 times.
|
2721 | if (update_equalities_for_sjm()) return true; |
| 3199 | } | ||
| 3200 |
2/2✓ Branch 0 taken 1815642 times.
✓ Branch 1 taken 96355 times.
|
1912019 | if (!plan_is_const()) { |
| 3201 | // Assign map of "available" tables to all tables belonging to query block | ||
| 3202 |
1/2✓ Branch 0 taken 1815642 times.
✗ Branch 1 not taken.
|
1815642 | set_prefix_tables(); |
| 3203 |
1/2✓ Branch 0 taken 1815641 times.
✗ Branch 1 not taken.
|
1815642 | adjust_access_methods(); |
| 3204 | } | ||
| 3205 | // Calculate outer join info | ||
| 3206 |
3/4✓ Branch 0 taken 150680 times.
✓ Branch 1 taken 1761316 times.
✓ Branch 2 taken 150680 times.
✗ Branch 3 not taken.
|
1911996 | if (query_block->outer_join) make_outerjoin_info(); |
| 3207 | |||
| 3208 | // sjm is no longer needed, trash it. To reuse it, reset its members! | ||
| 3209 |
7/12✓ Branch 0 taken 1911999 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1911999 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2783 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2783 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1914782 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2783 times.
✓ Branch 11 taken 1911999 times.
|
1914779 | for (TABLE_LIST *sj_nest : query_block->sj_nests) { |
| 3210 | 2783 | TRASH(static_cast<void *>(&sj_nest->nested_join->sjm), | |
| 3211 | sizeof(sj_nest->nested_join->sjm)); | ||
| 3212 | } | ||
| 3213 | |||
| 3214 | 1911999 | return false; | |
| 3215 | 1911999 | } | |
| 3216 | |||
| 3217 | /** | ||
| 3218 | Finds the dependencies of the remaining lateral derived tables. | ||
| 3219 | |||
| 3220 | @param plan_tables map of all tables that the planner is processing | ||
| 3221 | (tables already in plan and tables to be added to plan). | ||
| 3222 | @param idx index of the table which the planner is currently | ||
| 3223 | considering. | ||
| 3224 | @return A map of the dependencies of the remaining | ||
| 3225 | lateral derived tables (from best_ref[idx] and on). | ||
| 3226 | */ | ||
| 3227 | 7749 | table_map JOIN::calculate_deps_of_remaining_lateral_derived_tables( | |
| 3228 | table_map plan_tables, uint idx) const { | ||
| 3229 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7749 times.
|
7749 | assert(has_lateral); |
| 3230 | 7749 | table_map deps = 0; | |
| 3231 | 7749 | auto last = best_ref + tables; | |
| 3232 |
2/2✓ Branch 0 taken 27589 times.
✓ Branch 1 taken 7749 times.
|
35338 | for (auto **pos = best_ref + idx; pos < last; pos++) { |
| 3233 |
6/6✓ Branch 0 taken 26907 times.
✓ Branch 1 taken 682 times.
✓ Branch 2 taken 26898 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 26898 times.
✓ Branch 5 taken 691 times.
|
27589 | if ((*pos)->table_ref && ((*pos)->table_ref->map() & plan_tables)) { |
| 3234 | 26898 | deps |= get_lateral_deps(**pos); | |
| 3235 | } | ||
| 3236 | } | ||
| 3237 | 7749 | return deps; | |
| 3238 | } | ||
| 3239 | |||
| 3240 | /* | ||
| 3241 | Revise usage of join buffer for the specified table and the whole nest | ||
| 3242 | |||
| 3243 | SYNOPSIS | ||
| 3244 | revise_cache_usage() | ||
| 3245 | tab join table for which join buffer usage is to be revised | ||
| 3246 | |||
| 3247 | DESCRIPTION | ||
| 3248 | The function revise the decision to use a join buffer for the table 'tab'. | ||
| 3249 | If this table happened to be among the inner tables of a nested outer join/ | ||
| 3250 | semi-join the functions denies usage of join buffers for all of them | ||
| 3251 | |||
| 3252 | RETURN | ||
| 3253 | none | ||
| 3254 | */ | ||
| 3255 | |||
| 3256 | 1892237 | static void revise_cache_usage(JOIN_TAB *join_tab) { | |
| 3257 | 1892237 | plan_idx first_inner = join_tab->first_inner(); | |
| 3258 | 1892245 | JOIN *const join = join_tab->join(); | |
| 3259 |
2/2✓ Branch 0 taken 398163 times.
✓ Branch 1 taken 1494084 times.
|
1892247 | if (first_inner != NO_PLAN_IDX) { |
| 3260 | 398163 | plan_idx end_tab = join_tab->idx(); | |
| 3261 |
2/2✓ Branch 0 taken 398512 times.
✓ Branch 1 taken 398163 times.
|
796675 | for (first_inner = join_tab->first_inner(); first_inner != NO_PLAN_IDX; |
| 3262 | 398512 | first_inner = join->best_ref[first_inner]->first_upper()) { | |
| 3263 |
2/2✓ Branch 0 taken 2844 times.
✓ Branch 1 taken 398512 times.
|
401356 | for (plan_idx i = end_tab - 1; i >= first_inner; --i) |
| 3264 | 2844 | join->best_ref[i]->set_use_join_cache(JOIN_CACHE::ALG_NONE); | |
| 3265 | 398512 | end_tab = first_inner; | |
| 3266 | } | ||
| 3267 |
2/2✓ Branch 0 taken 437 times.
✓ Branch 1 taken 1493650 times.
|
1494084 | } else if (join_tab->get_sj_strategy() == SJ_OPT_FIRST_MATCH) { |
| 3268 | 437 | plan_idx first_sj_inner = join_tab->first_sj_inner(); | |
| 3269 |
2/2✓ Branch 0 taken 1744 times.
✓ Branch 1 taken 437 times.
|
2181 | for (plan_idx i = join_tab->idx() - 1; i >= first_sj_inner; --i) { |
| 3270 | 1744 | JOIN_TAB *tab = join->best_ref[i]; | |
| 3271 |
1/2✓ Branch 0 taken 1744 times.
✗ Branch 1 not taken.
|
1744 | if (tab->first_sj_inner() == first_sj_inner) |
| 3272 | 1744 | tab->set_use_join_cache(JOIN_CACHE::ALG_NONE); | |
| 3273 | } | ||
| 3274 | } else | ||
| 3275 | 1493650 | join_tab->set_use_join_cache(JOIN_CACHE::ALG_NONE); | |
| 3276 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1892241 times.
|
1892241 | assert(join->qep_tab == nullptr); |
| 3277 | 1892241 | } | |
| 3278 | |||
| 3279 | /** | ||
| 3280 | Set up join buffering for a specified table, if possible. | ||
| 3281 | |||
| 3282 | @param tab joined table to check join buffer usage for | ||
| 3283 | @param join join for which the check is performed | ||
| 3284 | @param no_jbuf_after don't use join buffering after table with this number | ||
| 3285 | |||
| 3286 | @return false if successful, true if error. | ||
| 3287 | Currently, allocation errors for join cache objects are ignored, | ||
| 3288 | and regular execution is chosen silently. | ||
| 3289 | |||
| 3290 | @details | ||
| 3291 | The function finds out whether the table 'tab' can be joined using a join | ||
| 3292 | buffer. This check is performed after the best execution plan for 'join' | ||
| 3293 | has been chosen. If the function decides that a join buffer can be employed | ||
| 3294 | then it selects the most appropriate join cache type, which later will | ||
| 3295 | be instantiated by init_join_cache(). | ||
| 3296 | If it has already been decided to not use join buffering for this table, | ||
| 3297 | no action is taken. | ||
| 3298 | |||
| 3299 | Often it is already decided that join buffering will be used earlier in | ||
| 3300 | the optimization process, and this will also ensure that the most correct | ||
| 3301 | cost for the operation is calculated, and hence the probability of | ||
| 3302 | choosing an optimal join plan is higher. However, some join buffering | ||
| 3303 | decisions cannot currently be taken before this stage, hence we need this | ||
| 3304 | function to decide the most accurate join buffering strategy. | ||
| 3305 | |||
| 3306 | @todo Long-term it is the goal that join buffering strategy is decided | ||
| 3307 | when the plan is selected. | ||
| 3308 | |||
| 3309 | The result of the check and the type of the join buffer to be used | ||
| 3310 | depend on: | ||
| 3311 | - the access method to access rows of the joined table | ||
| 3312 | - whether the join table is an inner table of an outer join or semi-join | ||
| 3313 | - the optimizer_switch settings for join buffering | ||
| 3314 | - the join 'options'. | ||
| 3315 | In any case join buffer is not used if the number of the joined table is | ||
| 3316 | greater than 'no_jbuf_after'. | ||
| 3317 | |||
| 3318 | If block_nested_loop is turned on, and if all other criteria for using | ||
| 3319 | join buffering is fulfilled (see below), then join buffer is used | ||
| 3320 | for any join operation (inner join, outer join, semi-join) with 'JT_ALL' | ||
| 3321 | access method. In that case, a JOIN_CACHE_BNL type is always employed. | ||
| 3322 | |||
| 3323 | If an index is used to access rows of the joined table and | ||
| 3324 | batched_key_access is on, then a JOIN_CACHE_BKA type is employed. | ||
| 3325 | |||
| 3326 | If the function decides that a join buffer can be used to join the table | ||
| 3327 | 'tab' then it sets @c tab->use_join_cache to reflect the chosen algorithm. | ||
| 3328 | |||
| 3329 | @note | ||
| 3330 | For a nested outer join/semi-join, currently, we either use join buffers for | ||
| 3331 | all inner tables or for none of them. | ||
| 3332 | |||
| 3333 | Join buffering is enabled for a few more cases for secondary engine. | ||
| 3334 | Currently if blocked nested loop(BNL) is employed for join buffering, | ||
| 3335 | it is replaced by hash joins in the executor. So the reasons for disabling | ||
| 3336 | join buffering because of the way BNL works are no more valid. This gives | ||
| 3337 | us an oppotunity to enable join buffering for more cases. However, | ||
| 3338 | we enable it only for secondary engine (in particular for semijoins), | ||
| 3339 | because of the following reasons: | ||
| 3340 | Secondary engine does not care about the cost based decisions | ||
| 3341 | involved in arriving at the best possible semijoin strategy; | ||
| 3342 | because it can only interpret a plan using "FirstMatch" strategy | ||
| 3343 | and can only do table scans. So the choices are very limited. | ||
| 3344 | However, it's not the case for mysql. There are serveral semijoin | ||
| 3345 | stratagies that could be picked. And these are picked based | ||
| 3346 | on the assumption that a nested-loop join(NLJ) would be used because | ||
| 3347 | optimizer currently generates plans only for NLJs and not | ||
| 3348 | hash joins. So, when executor replaces with hash joins, the number | ||
| 3349 | of rows that would be looked into for a particular semijoin strategy | ||
| 3350 | will differ from what the optimizer presumed while picking that | ||
| 3351 | strategy. | ||
| 3352 | For mysql server, we could enable join buffering for more cases, when | ||
| 3353 | a cost model for using hash joins is developed and optimizer could | ||
| 3354 | generate plans for hash joins. | ||
| 3355 | |||
| 3356 | @todo | ||
| 3357 | Support BKA inside SJ-Materialization nests. When doing this, we'll need | ||
| 3358 | to only store sj-inner tables in the join buffer. | ||
| 3359 | @verbatim | ||
| 3360 | JOIN_TAB *first_tab= join->join_tab+join->const_tables; | ||
| 3361 | uint n_tables= i-join->const_tables; | ||
| 3362 | / * | ||
| 3363 | We normally put all preceding tables into the join buffer, except | ||
| 3364 | for the constant tables. | ||
| 3365 | If we're inside a semi-join materialization nest, e.g. | ||
| 3366 | |||
| 3367 | outer_tbl1 outer_tbl2 ( inner_tbl1, inner_tbl2 ) ... | ||
| 3368 | ^-- we're here | ||
| 3369 | |||
| 3370 | then we need to put into the join buffer only the tables from | ||
| 3371 | within the nest. | ||
| 3372 | * / | ||
| 3373 | if (i >= first_sjm_table && i < last_sjm_table) | ||
| 3374 | { | ||
| 3375 | n_tables= i - first_sjm_table; // will be >0 if we got here | ||
| 3376 | first_tab= join->join_tab + first_sjm_table; | ||
| 3377 | } | ||
| 3378 | @endverbatim | ||
| 3379 | */ | ||
| 3380 | |||
| 3381 | 3826290 | static bool setup_join_buffering(JOIN_TAB *tab, JOIN *join, | |
| 3382 | uint no_jbuf_after) { | ||
| 3383 |
3/6✓ Branch 0 taken 3826294 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3826300 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3826306 times.
✗ Branch 5 not taken.
|
3826290 | ASSERT_BEST_REF_IN_JOIN_ORDER(join); |
| 3384 | 3826302 | Cost_estimate cost; | |
| 3385 | ha_rows rows; | ||
| 3386 | 3826298 | uint bufsz = 4096; | |
| 3387 | 3826298 | uint join_cache_flags = 0; | |
| 3388 |
1/2✓ Branch 0 taken 3826304 times.
✗ Branch 1 not taken.
|
3826298 | const bool bnl_on = hint_table_state(join->thd, tab->table_ref, BNL_HINT_ENUM, |
| 3389 | OPTIMIZER_SWITCH_BNL); | ||
| 3390 |
1/2✓ Branch 0 taken 3826311 times.
✗ Branch 1 not taken.
|
3826304 | const bool bka_on = hint_table_state(join->thd, tab->table_ref, BKA_HINT_ENUM, |
| 3391 | OPTIMIZER_SWITCH_BKA); | ||
| 3392 | |||
| 3393 | 3826311 | const uint tableno = tab->idx(); | |
| 3394 |
1/2✓ Branch 0 taken 3826313 times.
✗ Branch 1 not taken.
|
3826306 | const uint tab_sj_strategy = tab->get_sj_strategy(); |
| 3395 | |||
| 3396 | /* | ||
| 3397 | If all key_parts are null_rejecting, the MultiRangeRowIterator will | ||
| 3398 | eliminate all NULL values in the key set, such that | ||
| 3399 | HA_MRR_NO_NULL_ENDPOINTS can be promised. | ||
| 3400 | */ | ||
| 3401 | 3826313 | const key_part_map keypart_map = make_prev_keypart_map(tab->ref().key_parts); | |
| 3402 |
2/2✓ Branch 0 taken 2279581 times.
✓ Branch 1 taken 1546734 times.
|
3826314 | if (tab->ref().null_rejecting == keypart_map) { |
| 3403 | 2279581 | join_cache_flags |= HA_MRR_NO_NULL_ENDPOINTS; | |
| 3404 | } | ||
| 3405 | |||
| 3406 | // Set preliminary join cache setting based on decision from greedy search | ||
| 3407 |
2/2✓ Branch 0 taken 3810966 times.
✓ Branch 1 taken 15349 times.
|
3826315 | if (!join->select_count) |
| 3408 |
2/2✓ Branch 0 taken 171895 times.
✓ Branch 1 taken 3639073 times.
|
3810966 | tab->set_use_join_cache(tab->position()->use_join_buffer |
| 3409 | ? JOIN_CACHE::ALG_BNL | ||
| 3410 | : JOIN_CACHE::ALG_NONE); | ||
| 3411 | |||
| 3412 |
2/2✓ Branch 0 taken 1813739 times.
✓ Branch 1 taken 2012576 times.
|
3826315 | if (tableno == join->const_tables) { |
| 3413 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1813734 times.
|
1813739 | assert(tab->use_join_cache() == JOIN_CACHE::ALG_NONE); |
| 3414 | 1813734 | return false; | |
| 3415 | } | ||
| 3416 | |||
| 3417 |
4/4✓ Branch 0 taken 2248 times.
✓ Branch 1 taken 2010328 times.
✓ Branch 2 taken 541 times.
✓ Branch 3 taken 1707 times.
|
2012576 | if (!(bnl_on || bka_on)) goto no_join_cache; |
| 3418 | |||
| 3419 | /* | ||
| 3420 | psergey-todo: why the below when execution code seems to handle the | ||
| 3421 | "range checked for each record" case? | ||
| 3422 | */ | ||
| 3423 |
2/2✓ Branch 0 taken 356 times.
✓ Branch 1 taken 2011679 times.
|
2012035 | if (tab->use_quick == QS_DYNAMIC_RANGE) goto no_join_cache; |
| 3424 | |||
| 3425 | /* No join buffering if prevented by no_jbuf_after */ | ||
| 3426 |
2/2✓ Branch 0 taken 64333 times.
✓ Branch 1 taken 1947346 times.
|
2011679 | if (tableno > no_jbuf_after) goto no_join_cache; |
| 3427 | |||
| 3428 | /* | ||
| 3429 | An inner table of an outer join nest must not use join buffering if | ||
| 3430 | the first inner table of that outer join nest does not use join buffering. | ||
| 3431 | This condition is not handled by earlier optimizer stages. | ||
| 3432 | */ | ||
| 3433 |
8/8✓ Branch 0 taken 404419 times.
✓ Branch 1 taken 1542926 times.
✓ Branch 2 taken 1301 times.
✓ Branch 3 taken 403118 times.
✓ Branch 4 taken 639 times.
✓ Branch 5 taken 651 times.
✓ Branch 6 taken 639 times.
✓ Branch 7 taken 1946695 times.
|
1948636 | if (tab->first_inner() != NO_PLAN_IDX && tab->first_inner() != tab->idx() && |
| 3434 | 1301 | !join->best_ref[tab->first_inner()]->use_join_cache()) | |
| 3435 | 639 | goto no_join_cache; | |
| 3436 | /* | ||
| 3437 | The first inner table of an outer join nest must not use join buffering | ||
| 3438 | if the tables in the embedding outer join nest do not use join buffering. | ||
| 3439 | This condition is not handled by earlier optimizer stages. | ||
| 3440 | */ | ||
| 3441 |
6/6✓ Branch 0 taken 530 times.
✓ Branch 1 taken 1946171 times.
✓ Branch 2 taken 227 times.
✓ Branch 3 taken 300 times.
✓ Branch 4 taken 227 times.
✓ Branch 5 taken 1946471 times.
|
1947222 | if (tab->first_upper() != NO_PLAN_IDX && |
| 3442 | 530 | !join->best_ref[tab->first_upper()]->use_join_cache()) | |
| 3443 | 227 | goto no_join_cache; | |
| 3444 | |||
| 3445 |
6/6✓ Branch 0 taken 133 times.
✓ Branch 1 taken 1946336 times.
✓ Branch 2 taken 128 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 128 times.
✓ Branch 5 taken 1946341 times.
|
1946471 | if (tab->table()->pos_in_table_list->is_table_function() && tab->dependent) |
| 3446 | 128 | goto no_join_cache; | |
| 3447 | |||
| 3448 |
5/5✓ Branch 0 taken 323 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 2353 times.
✓ Branch 3 taken 1943646 times.
✓ Branch 4 taken 6 times.
|
1946341 | switch (tab_sj_strategy) { |
| 3449 | 323 | case SJ_OPT_FIRST_MATCH: | |
| 3450 | /* | ||
| 3451 | Use join cache with FirstMatch semi-join strategy only when semi-join | ||
| 3452 | contains only one table. | ||
| 3453 | As mentioned earlier (in comments), we lift this restriction for | ||
| 3454 | secondary engine. | ||
| 3455 | */ | ||
| 3456 |
3/6✓ Branch 0 taken 323 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 323 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 323 times.
✗ Branch 5 not taken.
|
646 | if (!(current_thd->lex->m_sql_cmd != nullptr && |
| 3457 |
2/4✓ Branch 0 taken 323 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 323 times.
✗ Branch 3 not taken.
|
323 | current_thd->lex->m_sql_cmd->using_secondary_storage_engine())) { |
| 3458 |
2/2✓ Branch 0 taken 124 times.
✓ Branch 1 taken 199 times.
|
323 | if (!tab->is_single_inner_of_semi_join()) { |
| 3459 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
|
124 | assert(tab->use_join_cache() == JOIN_CACHE::ALG_NONE); |
| 3460 | 124 | goto no_join_cache; | |
| 3461 | } | ||
| 3462 | } | ||
| 3463 | 199 | break; | |
| 3464 | |||
| 3465 | 13 | case SJ_OPT_LOOSE_SCAN: | |
| 3466 | /* No join buffering if this semijoin nest is handled by loosescan */ | ||
| 3467 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | assert(tab->use_join_cache() == JOIN_CACHE::ALG_NONE); |
| 3468 | 13 | goto no_join_cache; | |
| 3469 | |||
| 3470 | 2353 | case SJ_OPT_MATERIALIZE_LOOKUP: | |
| 3471 | case SJ_OPT_MATERIALIZE_SCAN: | ||
| 3472 | /* | ||
| 3473 | The Materialize strategies reuse the join_tab belonging to the | ||
| 3474 | first table that was materialized. Neither table can use join buffering: | ||
| 3475 | - The first table in a join never uses join buffering. | ||
| 3476 | - The join_tab used for looking up a row in the materialized table, or | ||
| 3477 | scanning the rows of a materialized table, cannot use join buffering. | ||
| 3478 | We allow join buffering for the remaining tables of the materialized | ||
| 3479 | semi-join nest. | ||
| 3480 | */ | ||
| 3481 |
2/2✓ Branch 0 taken 917 times.
✓ Branch 1 taken 1436 times.
|
2353 | if (tab->first_sj_inner() == tab->idx()) { |
| 3482 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 917 times.
|
917 | assert(tab->use_join_cache() == JOIN_CACHE::ALG_NONE); |
| 3483 | 917 | goto no_join_cache; | |
| 3484 | } | ||
| 3485 | 1436 | break; | |
| 3486 | |||
| 3487 | 1943646 | case SJ_OPT_DUPS_WEEDOUT: | |
| 3488 | // This strategy allows the same join buffering as a regular join would. | ||
| 3489 | case SJ_OPT_NONE: | ||
| 3490 | 1943646 | break; | |
| 3491 | } | ||
| 3492 | |||
| 3493 | /* | ||
| 3494 | The following code prevents use of join buffering when there is an | ||
| 3495 | outer join operation and first match semi-join strategy is used, because: | ||
| 3496 | |||
| 3497 | Outer join needs a "match flag" to track that a row should be | ||
| 3498 | NULL-complemented, such flag being attached to first inner table's cache | ||
| 3499 | (tracks whether the cached row from outer table got a match, in which case | ||
| 3500 | no NULL-complemented row is needed). | ||
| 3501 | |||
| 3502 | FirstMatch also needs a "match flag", such flag is attached to sj inner | ||
| 3503 | table's cache (tracks whether the cached row from outer table already got | ||
| 3504 | a first match in the sj-inner table, in which case we don't need to join | ||
| 3505 | this cached row again) | ||
| 3506 | - but a row in a cache has only one "match flag" | ||
| 3507 | - so if "sj inner table"=="first inner", there is a problem. | ||
| 3508 | |||
| 3509 | As mentioned earlier(in comments), we lift this restriction for | ||
| 3510 | secondary engine. | ||
| 3511 | */ | ||
| 3512 |
5/6✓ Branch 0 taken 1945282 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1932109 times.
✓ Branch 3 taken 13173 times.
✓ Branch 4 taken 1945181 times.
✓ Branch 5 taken 109 times.
|
3877404 | if (!(current_thd->lex->m_sql_cmd != nullptr && |
| 3513 |
3/4✓ Branch 0 taken 1932113 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1932008 times.
✓ Branch 3 taken 109 times.
|
1932109 | current_thd->lex->m_sql_cmd->using_secondary_storage_engine())) { |
| 3514 |
4/6✓ Branch 0 taken 199 times.
✓ Branch 1 taken 1944982 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 199 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1945181 times.
|
1945380 | if (tab_sj_strategy == SJ_OPT_FIRST_MATCH && |
| 3515 | 199 | tab->is_inner_table_of_outer_join()) | |
| 3516 | ✗ | goto no_join_cache; | |
| 3517 | } | ||
| 3518 | |||
| 3519 | 3890587 | if (join->deps_of_remaining_lateral_derived_tables & | |
| 3520 |
2/2✓ Branch 0 taken 634 times.
✓ Branch 1 taken 1944663 times.
|
1945290 | (tab->prefix_tables() & ~tab->added_tables())) { |
| 3521 | /* | ||
| 3522 | Even though the planner said "no jbuf please", the switch below may | ||
| 3523 | force it. | ||
| 3524 | If first-dependency-of-lateral-table < table-we-plan-for <= | ||
| 3525 | lateral-table, disable join buffering. | ||
| 3526 | Reason for this rule: | ||
| 3527 | consider a plan t1-t2-dt where dt is LATERAL and depends only on t1, and | ||
| 3528 | imagine t2 could do join buffering: then we buffer many rows of t1, then | ||
| 3529 | read one row of t2, fetch row#1 of t1 from cache, then materialize "dt" | ||
| 3530 | (as it depends on t1) and send row to client; then fetch row#2 of t1 | ||
| 3531 | from cache, rematerialize "dt": it's very inefficient. So we forbid join | ||
| 3532 | buffering on t2; this way, the signal "row of t1 changed" is emitted at | ||
| 3533 | the level of t1's operator, i.e. much less often, as one row of t1 may | ||
| 3534 | serve N rows of t2 before changing. | ||
| 3535 | On the other hand, t1 can do join buffering. | ||
| 3536 | A nice side-effect is to disable join buffering for "dt" itself. If | ||
| 3537 | "dt" would do join buffering: "dt" buffers many rows from t1/t2, then in a | ||
| 3538 | second phase we read one row from "dt" and join it with the many rows | ||
| 3539 | from t1/t2; but we cannot read a row from "dt" without first choosing a | ||
| 3540 | row of t1/t2 as "dt" depends on t1. | ||
| 3541 | See similar code in best_access_path(). | ||
| 3542 | */ | ||
| 3543 | 634 | goto no_join_cache; | |
| 3544 | } | ||
| 3545 | |||
| 3546 |
3/3✓ Branch 0 taken 120849 times.
✓ Branch 1 taken 1823784 times.
✓ Branch 2 taken 32 times.
|
1944663 | switch (tab->type()) { |
| 3547 | 120849 | case JT_ALL: | |
| 3548 | case JT_INDEX_SCAN: | ||
| 3549 | case JT_RANGE: | ||
| 3550 | case JT_INDEX_MERGE: | ||
| 3551 |
2/2✓ Branch 0 taken 748 times.
✓ Branch 1 taken 120101 times.
|
120849 | if (!bnl_on) { |
| 3552 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 748 times.
|
748 | assert(tab->use_join_cache() == JOIN_CACHE::ALG_NONE); |
| 3553 | 748 | goto no_join_cache; | |
| 3554 | } | ||
| 3555 | |||
| 3556 |
2/2✓ Branch 0 taken 120014 times.
✓ Branch 1 taken 87 times.
|
120101 | if (!join->select_count) tab->set_use_join_cache(JOIN_CACHE::ALG_BNL); |
| 3557 | 120101 | return false; | |
| 3558 | 1823784 | case JT_SYSTEM: | |
| 3559 | case JT_CONST: | ||
| 3560 | case JT_REF: | ||
| 3561 | case JT_EQ_REF: | ||
| 3562 |
2/2✓ Branch 0 taken 1822475 times.
✓ Branch 1 taken 1309 times.
|
1823784 | if (!bka_on) { |
| 3563 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1822469 times.
|
1822475 | assert(tab->use_join_cache() == JOIN_CACHE::ALG_NONE); |
| 3564 | 1822469 | goto no_join_cache; | |
| 3565 | } | ||
| 3566 | |||
| 3567 | /* | ||
| 3568 | Disable BKA for materializable derived tables/views as they aren't | ||
| 3569 | instantiated yet. | ||
| 3570 | */ | ||
| 3571 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1304 times.
|
1309 | if (tab->table_ref->uses_materialization()) goto no_join_cache; |
| 3572 | |||
| 3573 | /* | ||
| 3574 | Can't use BKA for subquery if dealing with a subquery that can | ||
| 3575 | turn a ref access into a "full scan on NULL key" table scan. | ||
| 3576 | |||
| 3577 | @see Item_in_optimizer::val_int() | ||
| 3578 | @see subselect_iterator_engine::exec() | ||
| 3579 | @see TABLE_REF::cond_guards | ||
| 3580 | @see push_index_cond() | ||
| 3581 | |||
| 3582 | @todo: This choice to not use BKA should be done before making | ||
| 3583 | cost estimates, e.g. in set_join_buffer_properties(). That | ||
| 3584 | happens before cond guards are set up, so instead of doing the | ||
| 3585 | check below, BKA should be disabled if | ||
| 3586 | - We are in an IN subquery, and | ||
| 3587 | - The IN predicate is not a top_level_item, and | ||
| 3588 | - The left_expr of the IN predicate may contain NULL values | ||
| 3589 | (left_expr->maybe_null) | ||
| 3590 | */ | ||
| 3591 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1304 times.
|
1304 | if (tab->has_guarded_conds()) goto no_join_cache; |
| 3592 | |||
| 3593 |
2/2✓ Branch 0 taken 503 times.
✓ Branch 1 taken 801 times.
|
1304 | if (tab->table()->covering_keys.is_set(tab->ref().key)) |
| 3594 | 503 | join_cache_flags |= HA_MRR_INDEX_ONLY; | |
| 3595 | 1304 | rows = tab->table()->file->multi_range_read_info( | |
| 3596 |
1/2✓ Branch 0 taken 1304 times.
✗ Branch 1 not taken.
|
1304 | tab->ref().key, 10, 20, &bufsz, &join_cache_flags, &cost); |
| 3597 | /* | ||
| 3598 | Cannot use BKA if | ||
| 3599 | 1. MRR scan cannot be performed, or | ||
| 3600 | 2. MRR default implementation is used, or | ||
| 3601 | 3. HA_MRR_NO_ASSOCIATION flag is set | ||
| 3602 | */ | ||
| 3603 |
1/2✓ Branch 0 taken 1304 times.
✗ Branch 1 not taken.
|
1304 | if ((rows == HA_POS_ERROR) || // 1 |
| 3604 |
2/2✓ Branch 0 taken 226 times.
✓ Branch 1 taken 1078 times.
|
1304 | (join_cache_flags & HA_MRR_USE_DEFAULT_IMPL) || // 2 |
| 3605 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 226 times.
|
226 | (join_cache_flags & HA_MRR_NO_ASSOCIATION)) // 3 |
| 3606 | 1078 | goto no_join_cache; | |
| 3607 | |||
| 3608 | 226 | tab->set_use_join_cache(JOIN_CACHE::ALG_BKA); | |
| 3609 | |||
| 3610 | 226 | tab->join_cache_flags = join_cache_flags; | |
| 3611 | 226 | return false; | |
| 3612 | default:; | ||
| 3613 | } | ||
| 3614 | |||
| 3615 | 1892244 | no_join_cache: | |
| 3616 |
1/2✓ Branch 0 taken 1892240 times.
✗ Branch 1 not taken.
|
1892244 | revise_cache_usage(tab); |
| 3617 | 1892240 | tab->set_use_join_cache(JOIN_CACHE::ALG_NONE); | |
| 3618 | 1892243 | return false; | |
| 3619 | } | ||
| 3620 | |||
| 3621 | /***************************************************************************** | ||
| 3622 | Make some simple condition optimization: | ||
| 3623 | If there is a test 'field = const' change all refs to 'field' to 'const' | ||
| 3624 | Remove all dummy tests 'item = item', 'const op const'. | ||
| 3625 | Remove all 'item is NULL', when item can never be null! | ||
| 3626 | Return in cond_value false if condition is impossible (1 = 2) | ||
| 3627 | *****************************************************************************/ | ||
| 3628 | |||
| 3629 | class COND_CMP : public ilink<COND_CMP> { | ||
| 3630 | public: | ||
| 3631 | 24 | static void *operator new(size_t size) { return (*THR_MALLOC)->Alloc(size); } | |
| 3632 | ✗ | static void operator delete(void *ptr [[maybe_unused]], | |
| 3633 | size_t size [[maybe_unused]]) { | ||
| 3634 | ✗ | TRASH(ptr, size); | |
| 3635 | } | ||
| 3636 | |||
| 3637 | Item *and_level; | ||
| 3638 | Item_func *cmp_func; | ||
| 3639 | 24 | COND_CMP(Item *a, Item_func *b) : and_level(a), cmp_func(b) {} | |
| 3640 | }; | ||
| 3641 | |||
| 3642 | 9381717 | Item_equal *find_item_equal(COND_EQUAL *cond_equal, | |
| 3643 | const Item_field *item_field, bool *inherited_fl) { | ||
| 3644 | 9381717 | Item_equal *item = nullptr; | |
| 3645 | 9381717 | bool in_upper_level = false; | |
| 3646 |
2/2✓ Branch 0 taken 10388239 times.
✓ Branch 1 taken 7841763 times.
|
18230002 | while (cond_equal) { |
| 3647 |
1/2✓ Branch 0 taken 10388292 times.
✗ Branch 1 not taken.
|
10388239 | List_iterator_fast<Item_equal> li(cond_equal->current_level); |
| 3648 |
2/2✓ Branch 0 taken 21881057 times.
✓ Branch 1 taken 8848285 times.
|
30729351 | while ((item = li++)) { |
| 3649 |
3/4✓ Branch 0 taken 21881142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1540083 times.
✓ Branch 3 taken 20341059 times.
|
21881057 | if (item->contains(item_field->field)) goto finish; |
| 3650 | } | ||
| 3651 | 8848285 | in_upper_level = true; | |
| 3652 | 8848285 | cond_equal = cond_equal->upper_levels; | |
| 3653 | } | ||
| 3654 | 7841763 | in_upper_level = false; | |
| 3655 | 9381846 | finish: | |
| 3656 | 9381846 | *inherited_fl = in_upper_level; | |
| 3657 | 9381846 | return item; | |
| 3658 | } | ||
| 3659 | |||
| 3660 | /** | ||
| 3661 | Get the best field substitution for a given field. | ||
| 3662 | |||
| 3663 | If the field is member of a multiple equality, look up that equality | ||
| 3664 | and return the most appropriate field. Usually this is the equivalenced | ||
| 3665 | field belonging to the outer-most table in the join order, but | ||
| 3666 | @see Item_field::get_subst_item() for details. | ||
| 3667 | Otherwise, return the same field. | ||
| 3668 | |||
| 3669 | @param item_field The field that we are seeking a substitution for. | ||
| 3670 | @param cond_equal multiple equalities to search in | ||
| 3671 | |||
| 3672 | @return The substituted field. | ||
| 3673 | */ | ||
| 3674 | |||
| 3675 | 1813516 | Item_field *get_best_field(Item_field *item_field, COND_EQUAL *cond_equal) { | |
| 3676 | bool dummy; | ||
| 3677 |
1/2✓ Branch 0 taken 1813534 times.
✗ Branch 1 not taken.
|
1813516 | Item_equal *item_eq = find_item_equal(cond_equal, item_field, &dummy); |
| 3678 |
2/2✓ Branch 0 taken 411915 times.
✓ Branch 1 taken 1401619 times.
|
1813534 | if (!item_eq) return item_field; |
| 3679 | |||
| 3680 |
1/2✓ Branch 0 taken 1401621 times.
✗ Branch 1 not taken.
|
1401619 | return item_eq->get_subst_item(item_field); |
| 3681 | } | ||
| 3682 | |||
| 3683 | /** | ||
| 3684 | Check whether an equality can be used to build multiple equalities. | ||
| 3685 | |||
| 3686 | This function first checks whether the equality (left_item=right_item) | ||
| 3687 | is a simple equality i.e. one that equates a field with another field | ||
| 3688 | or a constant (field=field_item or field=const_item). | ||
| 3689 | If this is the case the function looks for a multiple equality | ||
| 3690 | in the lists referenced directly or indirectly by cond_equal inferring | ||
| 3691 | the given simple equality. If it doesn't find any, it builds a multiple | ||
| 3692 | equality that covers the predicate, i.e. the predicate can be inferred | ||
| 3693 | from this multiple equality. | ||
| 3694 | The built multiple equality could be obtained in such a way: | ||
| 3695 | create a binary multiple equality equivalent to the predicate, then | ||
| 3696 | merge it, if possible, with one of old multiple equalities. | ||
| 3697 | This guarantees that the set of multiple equalities covering equality | ||
| 3698 | predicates will be minimal. | ||
| 3699 | |||
| 3700 | EXAMPLE: | ||
| 3701 | For the where condition | ||
| 3702 | @code | ||
| 3703 | WHERE a=b AND b=c AND | ||
| 3704 | (b=2 OR f=e) | ||
| 3705 | @endcode | ||
| 3706 | the check_equality will be called for the following equality | ||
| 3707 | predicates a=b, b=c, b=2 and f=e. | ||
| 3708 | - For a=b it will be called with *cond_equal=(0,[]) and will transform | ||
| 3709 | *cond_equal into (0,[Item_equal(a,b)]). | ||
| 3710 | - For b=c it will be called with *cond_equal=(0,[Item_equal(a,b)]) | ||
| 3711 | and will transform *cond_equal into CE=(0,[Item_equal(a,b,c)]). | ||
| 3712 | - For b=2 it will be called with *cond_equal=(ptr(CE),[]) | ||
| 3713 | and will transform *cond_equal into (ptr(CE),[Item_equal(2,a,b,c)]). | ||
| 3714 | - For f=e it will be called with *cond_equal=(ptr(CE), []) | ||
| 3715 | and will transform *cond_equal into (ptr(CE),[Item_equal(f,e)]). | ||
| 3716 | |||
| 3717 | @note | ||
| 3718 | Now only fields that have the same type definitions (verified by | ||
| 3719 | the Field::eq_def method) are placed to the same multiple equalities. | ||
| 3720 | Because of this some equality predicates are not eliminated and | ||
| 3721 | can be used in the constant propagation procedure. | ||
| 3722 | We could weaken the equality test as soon as at least one of the | ||
| 3723 | equal fields is to be equal to a constant. It would require a | ||
| 3724 | more complicated implementation: we would have to store, in | ||
| 3725 | general case, its own constant for each fields from the multiple | ||
| 3726 | equality. But at the same time it would allow us to get rid | ||
| 3727 | of constant propagation completely: it would be done by the call | ||
| 3728 | to build_equal_items_for_cond. | ||
| 3729 | |||
| 3730 | The implementation does not follow exactly the above rules to | ||
| 3731 | build a new multiple equality for the equality predicate. | ||
| 3732 | If it processes the equality of the form field1=field2, it | ||
| 3733 | looks for multiple equalities me1 containing field1 and me2 containing | ||
| 3734 | field2. If only one of them is found the function expands it with | ||
| 3735 | the lacking field. If multiple equalities for both fields are | ||
| 3736 | found they are merged. If both searches fail a new multiple equality | ||
| 3737 | containing just field1 and field2 is added to the existing | ||
| 3738 | multiple equalities. | ||
| 3739 | If the function processes the predicate of the form field1=const, | ||
| 3740 | it looks for a multiple equality containing field1. If found, the | ||
| 3741 | function checks the constant of the multiple equality. If the value | ||
| 3742 | is unknown, it is setup to const. Otherwise the value is compared with | ||
| 3743 | const and the evaluation of the equality predicate is performed. | ||
| 3744 | When expanding/merging equality predicates from the upper levels | ||
| 3745 | the function first copies them for the current level. It looks | ||
| 3746 | acceptable, as this happens rarely. The implementation without | ||
| 3747 | copying would be much more complicated. | ||
| 3748 | |||
| 3749 | @param thd Thread handler | ||
| 3750 | @param left_item left term of the equality to be checked | ||
| 3751 | @param right_item right term of the equality to be checked | ||
| 3752 | @param item equality item if the equality originates from a condition | ||
| 3753 | predicate, 0 if the equality is the result of row | ||
| 3754 | elimination | ||
| 3755 | @param cond_equal multiple equalities that must hold together with the | ||
| 3756 | equality | ||
| 3757 | @param[out] simple_equality | ||
| 3758 | true if the predicate is a simple equality predicate | ||
| 3759 | to be used for building multiple equalities | ||
| 3760 | false otherwise | ||
| 3761 | |||
| 3762 | @returns false if success, true if error | ||
| 3763 | */ | ||
| 3764 | |||
| 3765 | 5933255 | static bool check_simple_equality(THD *thd, Item *left_item, Item *right_item, | |
| 3766 | Item *item, COND_EQUAL *cond_equal, | ||
| 3767 | bool *simple_equality) { | ||
| 3768 | 5933255 | *simple_equality = false; | |
| 3769 | |||
| 3770 |
4/4✓ Branch 0 taken 299244 times.
✓ Branch 1 taken 5634089 times.
✓ Branch 2 taken 299101 times.
✓ Branch 3 taken 5634229 times.
|
6232496 | if (left_item->type() == Item::REF_ITEM && |
| 3771 |
2/2✓ Branch 0 taken 299095 times.
✓ Branch 1 taken 146 times.
|
299244 | down_cast<Item_ref *>(left_item)->ref_type() == Item_ref::VIEW_REF) { |
| 3772 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 299100 times.
|
299101 | if (down_cast<Item_ref *>(left_item)->is_outer_reference()) return false; |
| 3773 | 299100 | left_item = left_item->real_item(); | |
| 3774 | } | ||
| 3775 |
4/4✓ Branch 0 taken 7748 times.
✓ Branch 1 taken 5925533 times.
✓ Branch 2 taken 7679 times.
✓ Branch 3 taken 5925627 times.
|
5941107 | if (right_item->type() == Item::REF_ITEM && |
| 3776 |
2/2✓ Branch 0 taken 7679 times.
✓ Branch 1 taken 94 times.
|
7748 | down_cast<Item_ref *>(right_item)->ref_type() == Item_ref::VIEW_REF) { |
| 3777 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 7667 times.
|
7679 | if (down_cast<Item_ref *>(right_item)->is_outer_reference()) return false; |
| 3778 | 7667 | right_item = right_item->real_item(); | |
| 3779 | } | ||
| 3780 | const Item_field *left_item_field, *right_item_field; | ||
| 3781 | |||
| 3782 | 5933294 | if (left_item->type() == Item::FIELD_ITEM && | |
| 3783 |
4/4✓ Branch 0 taken 2095652 times.
✓ Branch 1 taken 3778655 times.
✓ Branch 2 taken 2095647 times.
✓ Branch 3 taken 1 times.
|
7969939 | right_item->type() == Item::FIELD_ITEM && |
| 3784 |
1/2✓ Branch 0 taken 2095654 times.
✗ Branch 1 not taken.
|
4191302 | (left_item_field = down_cast<const Item_field *>(left_item)) && |
| 3785 | 2095647 | (right_item_field = down_cast<const Item_field *>(right_item)) && | |
| 3786 |
8/8✓ Branch 0 taken 5874291 times.
✓ Branch 1 taken 59001 times.
✓ Branch 2 taken 2095502 times.
✓ Branch 3 taken 152 times.
✓ Branch 4 taken 2093097 times.
✓ Branch 5 taken 2405 times.
✓ Branch 6 taken 2093099 times.
✓ Branch 7 taken 3840208 times.
|
11807598 | !left_item_field->depended_from && !right_item_field->depended_from) { |
| 3787 | /* The predicate the form field1=field2 is processed */ | ||
| 3788 | |||
| 3789 | 2093099 | const Field *const left_field = left_item_field->field; | |
| 3790 | 2093099 | const Field *const right_field = right_item_field->field; | |
| 3791 | |||
| 3792 |
3/4✓ Branch 0 taken 2093094 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44699 times.
✓ Branch 3 taken 2048395 times.
|
2093099 | if (!left_field->eq_def(right_field)) return false; |
| 3793 | |||
| 3794 | /* Search for multiple equalities containing field1 and/or field2 */ | ||
| 3795 | bool left_copyfl, right_copyfl; | ||
| 3796 | Item_equal *left_item_equal = | ||
| 3797 |
1/2✓ Branch 0 taken 2048400 times.
✗ Branch 1 not taken.
|
2048395 | find_item_equal(cond_equal, left_item_field, &left_copyfl); |
| 3798 | Item_equal *right_item_equal = | ||
| 3799 |
1/2✓ Branch 0 taken 2048401 times.
✗ Branch 1 not taken.
|
2048400 | find_item_equal(cond_equal, right_item_field, &right_copyfl); |
| 3800 | |||
| 3801 | /* As (NULL=NULL) != TRUE we can't just remove the predicate f=f */ | ||
| 3802 |
3/4✓ Branch 0 taken 2048385 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
✓ Branch 3 taken 2048211 times.
|
2048401 | if (left_field->eq(right_field)) /* f = f */ |
| 3803 | { | ||
| 3804 | 174 | *simple_equality = | |
| 3805 |
6/6✓ Branch 0 taken 160 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 152 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 21 times.
|
174 | !((left_field->is_nullable() || left_field->table->is_nullable()) && |
| 3806 | !left_item_equal); | ||
| 3807 | 174 | return false; | |
| 3808 | } | ||
| 3809 | |||
| 3810 |
4/4✓ Branch 0 taken 116151 times.
✓ Branch 1 taken 1932060 times.
✓ Branch 2 taken 59 times.
✓ Branch 3 taken 116092 times.
|
2048211 | if (left_item_equal && left_item_equal == right_item_equal) { |
| 3811 | /* | ||
| 3812 | The equality predicate is inference of one of the existing | ||
| 3813 | multiple equalities, i.e the condition is already covered | ||
| 3814 | by upper level equalities | ||
| 3815 | */ | ||
| 3816 | 59 | *simple_equality = true; | |
| 3817 | 59 | return false; | |
| 3818 | } | ||
| 3819 | |||
| 3820 | /* Copy the found multiple equalities at the current level if needed */ | ||
| 3821 |
2/2✓ Branch 0 taken 114355 times.
✓ Branch 1 taken 1933797 times.
|
2048152 | if (left_copyfl) { |
| 3822 | /* left_item_equal of an upper level contains left_item */ | ||
| 3823 |
2/4✓ Branch 0 taken 114352 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 114357 times.
✗ Branch 3 not taken.
|
114355 | left_item_equal = new Item_equal(left_item_equal); |
| 3824 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 114357 times.
|
114357 | if (left_item_equal == nullptr) return true; |
| 3825 |
1/2✓ Branch 0 taken 114351 times.
✗ Branch 1 not taken.
|
114357 | cond_equal->current_level.push_back(left_item_equal); |
| 3826 | } | ||
| 3827 |
2/2✓ Branch 0 taken 139 times.
✓ Branch 1 taken 2048009 times.
|
2048148 | if (right_copyfl) { |
| 3828 | /* right_item_equal of an upper level contains right_item */ | ||
| 3829 |
2/4✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 139 times.
✗ Branch 3 not taken.
|
139 | right_item_equal = new Item_equal(right_item_equal); |
| 3830 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
|
139 | if (right_item_equal == nullptr) return true; |
| 3831 |
1/2✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
|
139 | cond_equal->current_level.push_back(right_item_equal); |
| 3832 | } | ||
| 3833 | |||
| 3834 |
2/2✓ Branch 0 taken 116087 times.
✓ Branch 1 taken 1932045 times.
|
2048132 | if (left_item_equal) { |
| 3835 | /* left item was found in the current or one of the upper levels */ | ||
| 3836 |
2/2✓ Branch 0 taken 116003 times.
✓ Branch 1 taken 84 times.
|
116087 | if (!right_item_equal) |
| 3837 |
1/2✓ Branch 0 taken 116006 times.
✗ Branch 1 not taken.
|
116003 | left_item_equal->add(down_cast<Item_field *>(right_item)); |
| 3838 | else { | ||
| 3839 | /* Merge two multiple equalities forming a new one */ | ||
| 3840 |
2/4✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
|
84 | if (left_item_equal->merge(thd, right_item_equal)) return true; |
| 3841 | /* Remove the merged multiple equality from the list */ | ||
| 3842 |
1/2✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
|
84 | List_iterator<Item_equal> li(cond_equal->current_level); |
| 3843 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 84 times.
|
156 | while ((li++) != right_item_equal) |
| 3844 | ; | ||
| 3845 |
1/2✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
|
84 | li.remove(); |
| 3846 | } | ||
| 3847 | } else { | ||
| 3848 | /* left item was not found neither the current nor in upper levels */ | ||
| 3849 |
2/2✓ Branch 0 taken 21444 times.
✓ Branch 1 taken 1910601 times.
|
1932045 | if (right_item_equal) { |
| 3850 |
1/2✓ Branch 0 taken 21445 times.
✗ Branch 1 not taken.
|
21444 | right_item_equal->add(down_cast<Item_field *>(left_item)); |
| 3851 | } else { | ||
| 3852 | /* None of the fields was found in multiple equalities */ | ||
| 3853 | Item_equal *item_equal = | ||
| 3854 | 1910601 | new Item_equal(down_cast<Item_field *>(left_item), | |
| 3855 |
2/4✓ Branch 0 taken 1910623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1910626 times.
✗ Branch 3 not taken.
|
1910620 | down_cast<Item_field *>(right_item)); |
| 3856 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1910626 times.
|
1910626 | if (item_equal == nullptr) return true; |
| 3857 |
1/2✓ Branch 0 taken 1910628 times.
✗ Branch 1 not taken.
|
1910626 | cond_equal->current_level.push_back(item_equal); |
| 3858 | } | ||
| 3859 | } | ||
| 3860 | 2048163 | *simple_equality = true; | |
| 3861 | 2048163 | return false; | |
| 3862 | } | ||
| 3863 | |||
| 3864 | { | ||
| 3865 | /* The predicate of the form field=const/const=field is processed */ | ||
| 3866 | 3840208 | Item *const_item = nullptr; | |
| 3867 | 3840208 | Item_field *field_item = nullptr; | |
| 3868 |
1/2✓ Branch 0 taken 3781212 times.
✗ Branch 1 not taken.
|
7621396 | if (left_item->type() == Item::FIELD_ITEM && |
| 3869 | 3781130 | (field_item = down_cast<Item_field *>(left_item)) && | |
| 3870 |
6/6✓ Branch 0 taken 3781130 times.
✓ Branch 1 taken 59028 times.
✓ Branch 2 taken 3780938 times.
✓ Branch 3 taken 274 times.
✓ Branch 4 taken 3773264 times.
✓ Branch 5 taken 66923 times.
|
11402255 | field_item->depended_from == nullptr && |
| 3871 |
2/2✓ Branch 0 taken 3773259 times.
✓ Branch 1 taken 7650 times.
|
3780938 | right_item->const_for_execution()) { |
| 3872 | 3773264 | const_item = right_item; | |
| 3873 |
1/2✓ Branch 0 taken 23639 times.
✗ Branch 1 not taken.
|
90562 | } else if (right_item->type() == Item::FIELD_ITEM && |
| 3874 | 23639 | (field_item = down_cast<Item_field *>(right_item)) && | |
| 3875 |
6/6✓ Branch 0 taken 23639 times.
✓ Branch 1 taken 43289 times.
✓ Branch 2 taken 20971 times.
✓ Branch 3 taken 2668 times.
✓ Branch 4 taken 19607 times.
✓ Branch 5 taken 47321 times.
|
111538 | field_item->depended_from == nullptr && |
| 3876 |
2/2✓ Branch 0 taken 19607 times.
✓ Branch 1 taken 1364 times.
|
20971 | left_item->const_for_execution()) { |
| 3877 | 19607 | const_item = left_item; | |
| 3878 | } | ||
| 3879 | |||
| 3880 | // Don't evaluate subqueries if they are disabled during optimization. | ||
| 3881 |
3/4✓ Branch 0 taken 3792857 times.
✓ Branch 1 taken 47335 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3840233 times.
|
7633090 | if (const_item != nullptr && |
| 3882 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3792898 times.
|
3792868 | !evaluate_during_optimization(const_item, |
| 3883 | 3792857 | thd->lex->current_query_block())) | |
| 3884 | ✗ | return false; | |
| 3885 | |||
| 3886 | /* | ||
| 3887 | If the constant expression contains a reference to the field | ||
| 3888 | (for example, a = (a IS NULL)), we don't want to replace the | ||
| 3889 | field with the constant expression as it makes the predicates | ||
| 3890 | more complex and may introduce cycles in the Item tree. | ||
| 3891 | */ | ||
| 3892 |
3/4✓ Branch 0 taken 3792909 times.
✓ Branch 1 taken 47324 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3840165 times.
|
7633074 | if (const_item != nullptr && |
| 3893 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3792841 times.
|
3792891 | const_item->walk(&Item::find_field_processor, enum_walk::POSTFIX, |
| 3894 | 3792909 | pointer_cast<uchar *>(field_item->field))) | |
| 3895 | ✗ | return false; | |
| 3896 | |||
| 3897 |
6/6✓ Branch 0 taken 3792873 times.
✓ Branch 1 taken 47292 times.
✓ Branch 2 taken 3782749 times.
✓ Branch 3 taken 10150 times.
✓ Branch 4 taken 3782744 times.
✓ Branch 5 taken 57447 times.
|
3840165 | if (const_item && field_item->result_type() == const_item->result_type()) { |
| 3898 |
3/4✓ Branch 0 taken 3782796 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 957233 times.
✓ Branch 3 taken 2825563 times.
|
3782744 | if (field_item->result_type() == STRING_RESULT) { |
| 3899 |
1/2✓ Branch 0 taken 957235 times.
✗ Branch 1 not taken.
|
957233 | const CHARSET_INFO *cs = field_item->field->charset(); |
| 3900 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 957235 times.
|
957235 | if (!item) { |
| 3901 | ✗ | Item_func_eq *const eq_item = new Item_func_eq(left_item, right_item); | |
| 3902 | ✗ | if (eq_item == nullptr || eq_item->set_cmp_func()) return true; | |
| 3903 | ✗ | eq_item->quick_fix_field(); | |
| 3904 | ✗ | item = eq_item; | |
| 3905 | } | ||
| 3906 |
5/6✓ Branch 0 taken 957234 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 956232 times.
✓ Branch 3 taken 1002 times.
✓ Branch 4 taken 311473 times.
✓ Branch 5 taken 645752 times.
|
1913458 | if ((cs != down_cast<Item_func *>(item)->compare_collation()) || |
| 3907 |
3/4✓ Branch 0 taken 956223 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 310471 times.
✓ Branch 3 taken 645752 times.
|
956232 | !cs->coll->propagate(cs, nullptr, 0)) |
| 3908 | 311473 | return false; | |
| 3909 | } | ||
| 3910 | |||
| 3911 | bool copyfl; | ||
| 3912 |
1/2✓ Branch 0 taken 3471324 times.
✗ Branch 1 not taken.
|
3471315 | Item_equal *item_equal = find_item_equal(cond_equal, field_item, ©fl); |
| 3913 |
2/2✓ Branch 0 taken 164 times.
✓ Branch 1 taken 3471160 times.
|
3471324 | if (copyfl) { |
| 3914 |
2/4✓ Branch 0 taken 164 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 164 times.
✗ Branch 3 not taken.
|
164 | item_equal = new Item_equal(item_equal); |
| 3915 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 164 times.
|
164 | if (item_equal == nullptr) return true; |
| 3916 |
1/2✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
|
164 | cond_equal->current_level.push_back(item_equal); |
| 3917 | } | ||
| 3918 |
2/2✓ Branch 0 taken 696 times.
✓ Branch 1 taken 3470611 times.
|
3471307 | if (item_equal) { |
| 3919 | /* | ||
| 3920 | The flag cond_false will be set to 1 after this, if item_equal | ||
| 3921 | already contains a constant and its value is not equal to | ||
| 3922 | the value of const_item. | ||
| 3923 | */ | ||
| 3924 |
3/4✓ Branch 0 taken 696 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 695 times.
|
696 | if (item_equal->add(thd, const_item, field_item)) return true; |
| 3925 | } else { | ||
| 3926 |
2/4✓ Branch 0 taken 3470613 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3470580 times.
✗ Branch 3 not taken.
|
3470611 | item_equal = new Item_equal(const_item, field_item); |
| 3927 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3470580 times.
|
3470580 | if (item_equal == nullptr) return true; |
| 3928 |
1/2✓ Branch 0 taken 3470624 times.
✗ Branch 1 not taken.
|
3470580 | cond_equal->current_level.push_back(item_equal); |
| 3929 | } | ||
| 3930 | 3471319 | *simple_equality = true; | |
| 3931 | 3471319 | return false; | |
| 3932 | } | ||
| 3933 | } | ||
| 3934 | 57447 | return false; | |
| 3935 | } | ||
| 3936 | |||
| 3937 | /** | ||
| 3938 | Convert row equalities into a conjunction of regular equalities. | ||
| 3939 | |||
| 3940 | The function converts a row equality of the form (E1,...,En)=(E'1,...,E'n) | ||
| 3941 | into a list of equalities E1=E'1,...,En=E'n. For each of these equalities | ||
| 3942 | Ei=E'i the function checks whether it is a simple equality or a row | ||
| 3943 | equality. If it is a simple equality it is used to expand multiple | ||
| 3944 | equalities of cond_equal. If it is a row equality it converted to a | ||
| 3945 | sequence of equalities between row elements. If Ei=E'i is neither a | ||
| 3946 | simple equality nor a row equality the item for this predicate is added | ||
| 3947 | to eq_list. | ||
| 3948 | |||
| 3949 | @param thd thread handle | ||
| 3950 | @param left_row left term of the row equality to be processed | ||
| 3951 | @param right_row right term of the row equality to be processed | ||
| 3952 | @param cond_equal multiple equalities that must hold together with the | ||
| 3953 | predicate | ||
| 3954 | @param eq_list results of conversions of row equalities that are not | ||
| 3955 | simple enough to form multiple equalities | ||
| 3956 | @param[out] simple_equality | ||
| 3957 | true if the row equality is composed of only | ||
| 3958 | simple equalities. | ||
| 3959 | |||
| 3960 | @returns false if conversion succeeded, true if any error. | ||
| 3961 | */ | ||
| 3962 | |||
| 3963 | 100 | static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row, | |
| 3964 | COND_EQUAL *cond_equal, List<Item> *eq_list, | ||
| 3965 | bool *simple_equality) { | ||
| 3966 | 100 | *simple_equality = false; | |
| 3967 | 100 | uint n = left_row->cols(); | |
| 3968 |
2/2✓ Branch 0 taken 224 times.
✓ Branch 1 taken 100 times.
|
324 | for (uint i = 0; i < n; i++) { |
| 3969 | bool is_converted; | ||
| 3970 |
1/2✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
|
224 | Item *left_item = left_row->element_index(i); |
| 3971 |
1/2✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
|
224 | Item *right_item = right_row->element_index(i); |
| 3972 |
3/6✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 224 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 224 times.
|
224 | if (left_item->type() == Item::ROW_ITEM && |
| 3973 | ✗ | right_item->type() == Item::ROW_ITEM) { | |
| 3974 | ✗ | if (check_row_equality(thd, down_cast<Item_row *>(left_item), | |
| 3975 | down_cast<Item_row *>(right_item), cond_equal, | ||
| 3976 | eq_list, &is_converted)) | ||
| 3977 | ✗ | return true; | |
| 3978 | ✗ | if (!is_converted) thd->lex->current_query_block()->cond_count++; | |
| 3979 | } else { | ||
| 3980 |
2/4✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 224 times.
|
224 | if (check_simple_equality(thd, left_item, right_item, nullptr, cond_equal, |
| 3981 | &is_converted)) | ||
| 3982 | ✗ | return true; | |
| 3983 | 224 | thd->lex->current_query_block()->cond_count++; | |
| 3984 | } | ||
| 3985 | |||
| 3986 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 206 times.
|
224 | if (!is_converted) { |
| 3987 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | Item_func_eq *const eq_item = new Item_func_eq(left_item, right_item); |
| 3988 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (eq_item == nullptr) return true; |
| 3989 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
|
18 | if (eq_item->set_cmp_func()) { |
| 3990 | // Failed to create cmp func -> not only simple equalitities | ||
| 3991 | ✗ | return true; | |
| 3992 | } | ||
| 3993 | 18 | eq_item->quick_fix_field(); | |
| 3994 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | eq_list->push_back(eq_item); |
| 3995 | } | ||
| 3996 | } | ||
| 3997 | 100 | *simple_equality = true; | |
| 3998 | 100 | return false; | |
| 3999 | } | ||
| 4000 | |||
| 4001 | /** | ||
| 4002 | Eliminate row equalities and form multiple equalities predicates. | ||
| 4003 | |||
| 4004 | This function checks whether the item is a simple equality | ||
| 4005 | i.e. the one that equates a field with another field or a constant | ||
| 4006 | (field=field_item or field=constant_item), or, a row equality. | ||
| 4007 | For a simple equality the function looks for a multiple equality | ||
| 4008 | in the lists referenced directly or indirectly by cond_equal inferring | ||
| 4009 | the given simple equality. If it doesn't find any, it builds/expands | ||
| 4010 | multiple equality that covers the predicate. | ||
| 4011 | Row equalities are eliminated substituted for conjunctive regular | ||
| 4012 | equalities which are treated in the same way as original equality | ||
| 4013 | predicates. | ||
| 4014 | |||
| 4015 | @param thd thread handle | ||
| 4016 | @param item predicate to process | ||
| 4017 | @param cond_equal multiple equalities that must hold together with the | ||
| 4018 | predicate | ||
| 4019 | @param eq_list results of conversions of row equalities that are not | ||
| 4020 | simple enough to form multiple equalities | ||
| 4021 | @param[out] equality | ||
| 4022 | true if re-writing rules have been applied | ||
| 4023 | false otherwise, i.e. | ||
| 4024 | if the predicate is not an equality, or | ||
| 4025 | if the equality is neither a simple nor a row equality | ||
| 4026 | |||
| 4027 | @returns false if success, true if error | ||
| 4028 | |||
| 4029 | @note If the equality was created by IN->EXISTS, it may be removed later by | ||
| 4030 | subquery materialization. So we don't mix this possibly temporary equality | ||
| 4031 | with others; if we let it go into a multiple-equality (Item_equal), then we | ||
| 4032 | could not remove it later. There is however an exception: if the outer | ||
| 4033 | expression is a constant, it is safe to leave the equality even in | ||
| 4034 | materialization; all it can do is preventing NULL/FALSE distinction but if | ||
| 4035 | such distinction mattered the equality would be in a triggered condition so | ||
| 4036 | we would not come to this function. And injecting constants is good because | ||
| 4037 | it makes the materialized table smaller. | ||
| 4038 | */ | ||
| 4039 | |||
| 4040 | 8891305 | static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal, | |
| 4041 | List<Item> *eq_list, bool *equality) { | ||
| 4042 | 8891305 | *equality = false; | |
| 4043 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8891397 times.
|
8891305 | assert(item->is_bool_func()); |
| 4044 | Item_func *item_func; | ||
| 4045 |
4/4✓ Branch 0 taken 8885794 times.
✓ Branch 1 taken 5588 times.
✓ Branch 2 taken 5933801 times.
✓ Branch 3 taken 2957503 times.
|
17777113 | if (item->type() == Item::FUNC_ITEM && |
| 4046 |
2/2✓ Branch 0 taken 5933756 times.
✓ Branch 1 taken 2951960 times.
|
8885794 | (item_func = down_cast<Item_func *>(item))->functype() == |
| 4047 | Item_func::EQ_FUNC) { | ||
| 4048 | 5933801 | Item *left_item = item_func->arguments()[0]; | |
| 4049 | 5933820 | Item *right_item = item_func->arguments()[1]; | |
| 4050 | |||
| 4051 |
6/6✓ Branch 0 taken 740 times.
✓ Branch 1 taken 5932999 times.
✓ Branch 2 taken 604 times.
✓ Branch 3 taken 136 times.
✓ Branch 4 taken 604 times.
✓ Branch 5 taken 5933135 times.
|
5933840 | if (item->created_by_in2exists() && !left_item->const_item()) |
| 4052 | 604 | return false; // See note above | |
| 4053 | |||
| 4054 |
4/4✓ Branch 0 taken 126 times.
✓ Branch 1 taken 5933011 times.
✓ Branch 2 taken 100 times.
✓ Branch 3 taken 5933044 times.
|
5933268 | if (left_item->type() == Item::ROW_ITEM && |
| 4055 |
2/2✓ Branch 0 taken 100 times.
✓ Branch 1 taken 33 times.
|
126 | right_item->type() == Item::ROW_ITEM) { |
| 4056 | 100 | thd->lex->current_query_block()->cond_count--; | |
| 4057 | 100 | return check_row_equality(thd, down_cast<Item_row *>(left_item), | |
| 4058 | down_cast<Item_row *>(right_item), cond_equal, | ||
| 4059 | 100 | eq_list, equality); | |
| 4060 | } else | ||
| 4061 | 5933044 | return check_simple_equality(thd, left_item, right_item, item, cond_equal, | |
| 4062 | 5933096 | equality); | |
| 4063 | } | ||
| 4064 | |||
| 4065 | 2957503 | return false; | |
| 4066 | } | ||
| 4067 | |||
| 4068 | /** | ||
| 4069 | Replace all equality predicates in a condition by multiple equality items. | ||
| 4070 | |||
| 4071 | At each 'and' level the function detects items for equality predicates | ||
| 4072 | and replaces them by a set of multiple equality items of class Item_equal, | ||
| 4073 | taking into account inherited equalities from upper levels. | ||
| 4074 | If an equality predicate is used not in a conjunction it's just | ||
| 4075 | replaced by a multiple equality predicate. | ||
| 4076 | For each 'and' level the function set a pointer to the inherited | ||
| 4077 | multiple equalities in the cond_equal field of the associated | ||
| 4078 | object of the type Item_cond_and. | ||
| 4079 | The function also traverses the cond tree and for each field reference | ||
| 4080 | sets a pointer to the multiple equality item containing the field, if there | ||
| 4081 | is any. If this multiple equality equates fields to a constant the | ||
| 4082 | function replaces the field reference by the constant in the cases | ||
| 4083 | when the field is not of a string type or when the field reference is | ||
| 4084 | just an argument of a comparison predicate. | ||
| 4085 | The function also determines the maximum number of members in | ||
| 4086 | equality lists of each Item_cond_and object assigning it to | ||
| 4087 | thd->lex->current_query_block()->max_equal_elems. | ||
| 4088 | |||
| 4089 | @note | ||
| 4090 | Multiple equality predicate =(f1,..fn) is equivalent to the conjunction of | ||
| 4091 | f1=f2, .., fn-1=fn. It substitutes any inference from these | ||
| 4092 | equality predicates that is equivalent to the conjunction. | ||
| 4093 | Thus, =(a1,a2,a3) can substitute for ((a1=a3) AND (a2=a3) AND (a2=a1)) as | ||
| 4094 | it is equivalent to ((a1=a2) AND (a2=a3)). | ||
| 4095 | The function always makes a substitution of all equality predicates occurred | ||
| 4096 | in a conjunction for a minimal set of multiple equality predicates. | ||
| 4097 | This set can be considered as a canonical representation of the | ||
| 4098 | sub-conjunction of the equality predicates. | ||
| 4099 | E.g. (t1.a=t2.b AND t2.b>5 AND t1.a=t3.c) is replaced by | ||
| 4100 | (=(t1.a,t2.b,t3.c) AND t2.b>5), not by | ||
| 4101 | (=(t1.a,t2.b) AND =(t1.a,t3.c) AND t2.b>5); | ||
| 4102 | while (t1.a=t2.b AND t2.b>5 AND t3.c=t4.d) is replaced by | ||
| 4103 | (=(t1.a,t2.b) AND =(t3.c=t4.d) AND t2.b>5), | ||
| 4104 | but if additionally =(t4.d,t2.b) is inherited, it | ||
| 4105 | will be replaced by (=(t1.a,t2.b,t3.c,t4.d) AND t2.b>5) | ||
| 4106 | |||
| 4107 | The function performs the substitution in a recursive descent of | ||
| 4108 | the condition tree, passing to the next AND level a chain of multiple | ||
| 4109 | equality predicates which have been built at the upper levels. | ||
| 4110 | The Item_equal items built at the level are attached to other | ||
| 4111 | non-equality conjuncts as a sublist. The pointer to the inherited | ||
| 4112 | multiple equalities is saved in the and condition object (Item_cond_and). | ||
| 4113 | This chain allows us for any field reference occurrence to easily find a | ||
| 4114 | multiple equality that must be held for this occurrence. | ||
| 4115 | For each AND level we do the following: | ||
| 4116 | - scan it for all equality predicate (=) items | ||
| 4117 | - join them into disjoint Item_equal() groups | ||
| 4118 | - process the included OR conditions recursively to do the same for | ||
| 4119 | lower AND levels. | ||
| 4120 | |||
| 4121 | We need to do things in this order as lower AND levels need to know about | ||
| 4122 | all possible Item_equal objects in upper levels. | ||
| 4123 | |||
| 4124 | @param thd thread handle | ||
| 4125 | @param cond condition(expression) where to make replacement | ||
| 4126 | @param[out] retcond returned condition | ||
| 4127 | @param inherited path to all inherited multiple equality items | ||
| 4128 | @param do_inherit whether or not to inherit equalities from other parts | ||
| 4129 | of the condition | ||
| 4130 | |||
| 4131 | @returns false if success, true if error | ||
| 4132 | */ | ||
| 4133 | |||
| 4134 | 4707341 | static bool build_equal_items_for_cond(THD *thd, Item *cond, Item **retcond, | |
| 4135 | COND_EQUAL *inherited, bool do_inherit) { | ||
| 4136 | Item_equal *item_equal; | ||
| 4137 |
1/2✓ Branch 0 taken 4707391 times.
✗ Branch 1 not taken.
|
4707341 | COND_EQUAL cond_equal; |
| 4138 | 4707391 | cond_equal.upper_levels = inherited; | |
| 4139 |
2/4✓ Branch 0 taken 4707353 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4707353 times.
|
4707391 | assert(cond->is_bool_func()); |
| 4140 |
2/4✓ Branch 0 taken 4707440 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4707440 times.
|
4707353 | if (check_stack_overrun(thd, STACK_MIN_SIZE, nullptr)) |
| 4141 | ✗ | return true; // Fatal error flag is set! | |
| 4142 | |||
| 4143 |
1/2✓ Branch 0 taken 4707377 times.
✗ Branch 1 not taken.
|
4707440 | const enum Item::Type cond_type = cond->type(); |
| 4144 |
2/2✓ Branch 0 taken 1959456 times.
✓ Branch 1 taken 2747921 times.
|
4707377 | if (cond_type == Item::COND_ITEM) { |
| 4145 | 1959456 | List<Item> eq_list; | |
| 4146 | 1959451 | Item_cond *const item_cond = down_cast<Item_cond *>(cond); | |
| 4147 |
1/2✓ Branch 0 taken 1959450 times.
✗ Branch 1 not taken.
|
1959447 | const bool and_level = item_cond->functype() == Item_func::COND_AND_FUNC; |
| 4148 | 1959450 | List<Item> *args = item_cond->argument_list(); | |
| 4149 | |||
| 4150 |
1/2✓ Branch 0 taken 1959456 times.
✗ Branch 1 not taken.
|
1959456 | List_iterator<Item> li(*args); |
| 4151 | Item *item; | ||
| 4152 | |||
| 4153 |
2/2✓ Branch 0 taken 1929778 times.
✓ Branch 1 taken 29678 times.
|
1959456 | if (and_level) { |
| 4154 | /* | ||
| 4155 | Retrieve all conjuncts of this level detecting the equality | ||
| 4156 | that are subject to substitution by multiple equality items and | ||
| 4157 | removing each such predicate from the conjunction after having | ||
| 4158 | found/created a multiple equality whose inference the predicate is. | ||
| 4159 | */ | ||
| 4160 |
2/2✓ Branch 0 taken 6143521 times.
✓ Branch 1 taken 1929775 times.
|
8073294 | while ((item = li++)) { |
| 4161 | /* | ||
| 4162 | PS/SP note: we can safely remove a node from AND-OR | ||
| 4163 | structure here because it's restored before each | ||
| 4164 | re-execution of any prepared statement/stored procedure. | ||
| 4165 | */ | ||
| 4166 | bool equality; | ||
| 4167 |
3/4✓ Branch 0 taken 6143511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 6143510 times.
|
6143521 | if (check_equality(thd, item, &cond_equal, &eq_list, &equality)) |
| 4168 | 1 | return true; | |
| 4169 |
3/4✓ Branch 0 taken 4617641 times.
✓ Branch 1 taken 1525869 times.
✓ Branch 2 taken 4617647 times.
✗ Branch 3 not taken.
|
6143510 | if (equality) li.remove(); |
| 4170 | } | ||
| 4171 | |||
| 4172 | /* | ||
| 4173 | Check if we eliminated all the predicates of the level, e.g. | ||
| 4174 | (a=a AND b=b AND a=a). | ||
| 4175 | */ | ||
| 4176 |
4/4✓ Branch 0 taken 1264023 times.
✓ Branch 1 taken 665752 times.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 1263978 times.
|
1929775 | if (!args->elements && !cond_equal.current_level.elements && |
| 4177 |
1/2✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
|
45 | !eq_list.elements) { |
| 4178 |
1/2✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
|
90 | *retcond = new Item_func_true(); |
| 4179 | 45 | return *retcond == nullptr; | |
| 4180 | } | ||
| 4181 | |||
| 4182 |
1/2✓ Branch 0 taken 1929728 times.
✗ Branch 1 not taken.
|
1929730 | List_iterator_fast<Item_equal> it(cond_equal.current_level); |
| 4183 |
2/2✓ Branch 0 taken 4593795 times.
✓ Branch 1 taken 1929730 times.
|
6523524 | while ((item_equal = it++)) { |
| 4184 |
2/4✓ Branch 0 taken 4593780 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4593780 times.
|
4593795 | if (item_equal->resolve_type(thd)) return true; |
| 4185 |
1/2✓ Branch 0 taken 4593802 times.
✗ Branch 1 not taken.
|
4593780 | item_equal->update_used_tables(); |
| 4186 | 9187584 | thd->lex->current_query_block()->max_equal_elems = | |
| 4187 | 4593802 | std::max(thd->lex->current_query_block()->max_equal_elems, | |
| 4188 |
1/2✓ Branch 0 taken 4593801 times.
✗ Branch 1 not taken.
|
9187598 | item_equal->members()); |
| 4189 | } | ||
| 4190 | |||
| 4191 | 1929730 | Item_cond_and *const item_cond_and = down_cast<Item_cond_and *>(cond); | |
| 4192 |
1/2✓ Branch 0 taken 1929721 times.
✗ Branch 1 not taken.
|
1929723 | item_cond_and->cond_equal = cond_equal; |
| 4193 | 1929721 | inherited = &item_cond_and->cond_equal; | |
| 4194 | } | ||
| 4195 | /* | ||
| 4196 | Make replacement of equality predicates for lower levels | ||
| 4197 | of the condition expression. | ||
| 4198 | */ | ||
| 4199 | 1959399 | li.rewind(); | |
| 4200 |
2/2✓ Branch 0 taken 2545553 times.
✓ Branch 1 taken 1959407 times.
|
4504947 | while ((item = li++)) { |
| 4201 | Item *new_item; | ||
| 4202 |
2/4✓ Branch 0 taken 2545543 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2545543 times.
|
2545553 | if (build_equal_items_for_cond(thd, item, &new_item, inherited, |
| 4203 | do_inherit)) | ||
| 4204 | ✗ | return true; | |
| 4205 |
2/2✓ Branch 0 taken 10734 times.
✓ Branch 1 taken 2534809 times.
|
2545543 | if (new_item != item) { |
| 4206 | /* This replacement happens only for standalone equalities */ | ||
| 4207 | /* | ||
| 4208 | This is ok with PS/SP as the replacement is done for | ||
| 4209 | arguments of an AND/OR item, which are restored for each | ||
| 4210 | execution of PS/SP. | ||
| 4211 | */ | ||
| 4212 | 10734 | li.replace(new_item); | |
| 4213 | } | ||
| 4214 | } | ||
| 4215 |
2/2✓ Branch 0 taken 1929732 times.
✓ Branch 1 taken 29675 times.
|
1959407 | if (and_level) { |
| 4216 |
1/2✓ Branch 0 taken 1929724 times.
✗ Branch 1 not taken.
|
1929732 | args->concat(&eq_list); |
| 4217 |
1/2✓ Branch 0 taken 1929736 times.
✗ Branch 1 not taken.
|
1929724 | args->concat((List<Item> *)&cond_equal.current_level); |
| 4218 | } | ||
| 4219 |
3/4✓ Branch 0 taken 2747904 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2747809 times.
✓ Branch 3 taken 95 times.
|
2747921 | } else if (cond->type() == Item::FUNC_ITEM) { |
| 4220 | 2747809 | List<Item> eq_list; | |
| 4221 | /* | ||
| 4222 | If an equality predicate forms the whole and level, | ||
| 4223 | we call it standalone equality and it's processed here. | ||
| 4224 | E.g. in the following where condition | ||
| 4225 | WHERE a=5 AND (b=5 or a=c) | ||
| 4226 | (b=5) and (a=c) are standalone equalities. | ||
| 4227 | In general we can't leave alone standalone eqalities: | ||
| 4228 | for WHERE a=b AND c=d AND (b=c OR d=5) | ||
| 4229 | b=c is replaced by =(a,b,c,d). | ||
| 4230 | */ | ||
| 4231 | bool equality; | ||
| 4232 |
2/4✓ Branch 0 taken 2747841 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2747841 times.
|
2747838 | if (check_equality(thd, cond, &cond_equal, &eq_list, &equality)) |
| 4233 | 901901 | return true; | |
| 4234 |
2/2✓ Branch 0 taken 901929 times.
✓ Branch 1 taken 1845912 times.
|
2747841 | if (equality) { |
| 4235 | 901929 | int n = cond_equal.current_level.elements + eq_list.elements; | |
| 4236 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 901905 times.
|
901929 | if (n == 0) { |
| 4237 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
48 | *retcond = new Item_func_true(); |
| 4238 | 24 | return *retcond == nullptr; | |
| 4239 |
2/2✓ Branch 0 taken 901807 times.
✓ Branch 1 taken 98 times.
|
901905 | } else if (n == 1) { |
| 4240 |
2/2✓ Branch 0 taken 901808 times.
✓ Branch 1 taken 7 times.
|
901807 | if ((item_equal = cond_equal.current_level.pop())) { |
| 4241 |
2/4✓ Branch 0 taken 901772 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 901772 times.
|
901808 | if (item_equal->resolve_type(thd)) return true; |
| 4242 |
1/2✓ Branch 0 taken 901840 times.
✗ Branch 1 not taken.
|
901772 | item_equal->update_used_tables(); |
| 4243 | 1803565 | thd->lex->current_query_block()->max_equal_elems = | |
| 4244 | 901765 | std::max(thd->lex->current_query_block()->max_equal_elems, | |
| 4245 |
1/2✓ Branch 0 taken 901751 times.
✗ Branch 1 not taken.
|
901840 | item_equal->members()); |
| 4246 | 901777 | *retcond = item_equal; | |
| 4247 | 901777 | return false; | |
| 4248 | } | ||
| 4249 | |||
| 4250 | 7 | *retcond = eq_list.pop(); | |
| 4251 | ✗ | return false; | |
| 4252 | } else { | ||
| 4253 | /* | ||
| 4254 | Here a new AND level must be created. It can happen only | ||
| 4255 | when a row equality is processed as a standalone predicate. | ||
| 4256 | */ | ||
| 4257 |
2/4✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100 times.
✗ Branch 3 not taken.
|
98 | Item_cond_and *and_cond = new Item_cond_and(eq_list); |
| 4258 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
|
100 | if (and_cond == nullptr) return true; |
| 4259 | |||
| 4260 | 100 | and_cond->quick_fix_field(); | |
| 4261 | 100 | List<Item> *args = and_cond->argument_list(); | |
| 4262 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | List_iterator_fast<Item_equal> it(cond_equal.current_level); |
| 4263 |
2/2✓ Branch 0 taken 206 times.
✓ Branch 1 taken 100 times.
|
306 | while ((item_equal = it++)) { |
| 4264 |
2/4✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 206 times.
|
206 | if (item_equal->resolve_type(thd)) return true; |
| 4265 |
1/2✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
|
206 | item_equal->update_used_tables(); |
| 4266 | 412 | thd->lex->current_query_block()->max_equal_elems = | |
| 4267 | 206 | std::max(thd->lex->current_query_block()->max_equal_elems, | |
| 4268 |
1/2✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
|
412 | item_equal->members()); |
| 4269 | } | ||
| 4270 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | and_cond->cond_equal = cond_equal; |
| 4271 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | args->concat((List<Item> *)&cond_equal.current_level); |
| 4272 | |||
| 4273 | 100 | *retcond = and_cond; | |
| 4274 | 100 | return false; | |
| 4275 | } | ||
| 4276 | } | ||
| 4277 | |||
| 4278 |
2/2✓ Branch 0 taken 1845898 times.
✓ Branch 1 taken 14 times.
|
1845912 | if (do_inherit) { |
| 4279 | /* | ||
| 4280 | For each field reference in cond, not from equal item predicates, | ||
| 4281 | set a pointer to the multiple equality it belongs to (if there is any) | ||
| 4282 | as soon the field is not of a string type or the field reference is | ||
| 4283 | an argument of a comparison predicate. | ||
| 4284 | */ | ||
| 4285 | 1845898 | uchar *is_subst_valid = (uchar *)1; | |
| 4286 |
1/2✓ Branch 0 taken 1845911 times.
✗ Branch 1 not taken.
|
1845898 | cond = cond->compile(&Item::subst_argument_checker, &is_subst_valid, |
| 4287 | &Item::equal_fields_propagator, (uchar *)inherited); | ||
| 4288 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1845911 times.
|
1845911 | if (cond == nullptr) return true; |
| 4289 | } | ||
| 4290 |
1/2✓ Branch 0 taken 1845912 times.
✗ Branch 1 not taken.
|
1845925 | cond->update_used_tables(); |
| 4291 | } | ||
| 4292 | 3805418 | *retcond = cond; | |
| 4293 | 3805418 | return false; | |
| 4294 | } | ||
| 4295 | |||
| 4296 | /** | ||
| 4297 | Build multiple equalities for a WHERE condition and all join conditions that | ||
| 4298 | inherit these multiple equalities. | ||
| 4299 | |||
| 4300 | The function first applies the build_equal_items_for_cond function | ||
| 4301 | to build all multiple equalities for condition cond utilizing equalities | ||
| 4302 | referred through the parameter inherited. The extended set of | ||
| 4303 | equalities is returned in the structure referred by the cond_equal_ref | ||
| 4304 | parameter. After this the function calls itself recursively for | ||
| 4305 | all join conditions whose direct references can be found in join_list | ||
| 4306 | and who inherit directly the multiple equalities just having built. | ||
| 4307 | |||
| 4308 | @note | ||
| 4309 | The join condition used in an outer join operation inherits all equalities | ||
| 4310 | from the join condition of the embedding join, if there is any, or | ||
| 4311 | otherwise - from the where condition. | ||
| 4312 | This fact is not obvious, but presumably can be proved. | ||
| 4313 | Consider the following query: | ||
| 4314 | @code | ||
| 4315 | SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t1.a=t3.a AND t2.a=t4.a | ||
| 4316 | WHERE t1.a=t2.a; | ||
| 4317 | @endcode | ||
| 4318 | If the join condition in the query inherits =(t1.a,t2.a), then we | ||
| 4319 | can build the multiple equality =(t1.a,t2.a,t3.a,t4.a) that infers | ||
| 4320 | the equality t3.a=t4.a. Although the join condition | ||
| 4321 | t1.a=t3.a AND t2.a=t4.a AND t3.a=t4.a is not equivalent to the one | ||
| 4322 | in the query the latter can be replaced by the former: the new query | ||
| 4323 | will return the same result set as the original one. | ||
| 4324 | |||
| 4325 | Interesting that multiple equality =(t1.a,t2.a,t3.a,t4.a) allows us | ||
| 4326 | to use t1.a=t3.a AND t3.a=t4.a under the join condition: | ||
| 4327 | @code | ||
| 4328 | SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t1.a=t3.a AND t3.a=t4.a | ||
| 4329 | WHERE t1.a=t2.a | ||
| 4330 | @endcode | ||
| 4331 | This query equivalent to: | ||
| 4332 | @code | ||
| 4333 | SELECT * FROM (t1 LEFT JOIN (t3,t4) ON t1.a=t3.a AND t3.a=t4.a),t2 | ||
| 4334 | WHERE t1.a=t2.a | ||
| 4335 | @endcode | ||
| 4336 | Similarly the original query can be rewritten to the query: | ||
| 4337 | @code | ||
| 4338 | SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t2.a=t4.a AND t3.a=t4.a | ||
| 4339 | WHERE t1.a=t2.a | ||
| 4340 | @endcode | ||
| 4341 | that is equivalent to: | ||
| 4342 | @code | ||
| 4343 | SELECT * FROM (t2 LEFT JOIN (t3,t4)ON t2.a=t4.a AND t3.a=t4.a), t1 | ||
| 4344 | WHERE t1.a=t2.a | ||
| 4345 | @endcode | ||
| 4346 | Thus, applying equalities from the where condition we basically | ||
| 4347 | can get more freedom in performing join operations. | ||
| 4348 | Although we don't use this property now, it probably makes sense to use | ||
| 4349 | it in the future. | ||
| 4350 | |||
| 4351 | @param thd Thread handler | ||
| 4352 | @param cond condition to build the multiple equalities for | ||
| 4353 | @param[out] retcond Returned condition | ||
| 4354 | @param inherited path to all inherited multiple equality items | ||
| 4355 | @param do_inherit whether or not to inherit equalities from other | ||
| 4356 | parts of the condition | ||
| 4357 | @param join_list list of join tables that the condition refers to | ||
| 4358 | @param[out] cond_equal_ref pointer to the structure to place built | ||
| 4359 | equalities in | ||
| 4360 | |||
| 4361 | @returns false if success, true if error | ||
| 4362 | */ | ||
| 4363 | |||
| 4364 | 2165727 | bool build_equal_items(THD *thd, Item *cond, Item **retcond, | |
| 4365 | COND_EQUAL *inherited, bool do_inherit, | ||
| 4366 | mem_root_deque<TABLE_LIST *> *join_list, | ||
| 4367 | COND_EQUAL **cond_equal_ref) { | ||
| 4368 | 2165727 | COND_EQUAL *cond_equal = nullptr; | |
| 4369 | |||
| 4370 |
2/2✓ Branch 0 taken 2161787 times.
✓ Branch 1 taken 3940 times.
|
2165727 | if (cond) { |
| 4371 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2161816 times.
|
2161787 | if (build_equal_items_for_cond(thd, cond, &cond, inherited, do_inherit)) |
| 4372 | 1 | return true; | |
| 4373 | 2161816 | cond->update_used_tables(); | |
| 4374 | // update_used_tables() returns void but can still fail. | ||
| 4375 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2161879 times.
|
2161889 | if (thd->is_error()) return true; |
| 4376 | |||
| 4377 | 2161879 | const enum Item::Type cond_type = cond->type(); | |
| 4378 |
4/4✓ Branch 0 taken 993100 times.
✓ Branch 1 taken 1168750 times.
✓ Branch 2 taken 968989 times.
✓ Branch 3 taken 1192875 times.
|
3154964 | if (cond_type == Item::COND_ITEM && |
| 4379 |
2/2✓ Branch 0 taken 969000 times.
✓ Branch 1 taken 24114 times.
|
993100 | down_cast<Item_cond *>(cond)->functype() == Item_func::COND_AND_FUNC) |
| 4380 | 968989 | cond_equal = &down_cast<Item_cond_and *>(cond)->cond_equal; | |
| 4381 |
4/4✓ Branch 0 taken 1168600 times.
✓ Branch 1 taken 24275 times.
✓ Branch 2 taken 891174 times.
✓ Branch 3 taken 301652 times.
|
2361426 | else if (cond_type == Item::FUNC_ITEM && |
| 4382 |
2/2✓ Branch 0 taken 891149 times.
✓ Branch 1 taken 277402 times.
|
1168600 | down_cast<Item_func *>(cond)->functype() == |
| 4383 | Item_func::MULT_EQUAL_FUNC) { | ||
| 4384 |
2/4✓ Branch 0 taken 891172 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 891177 times.
✗ Branch 3 not taken.
|
891174 | cond_equal = new (thd->mem_root) COND_EQUAL; |
| 4385 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 891177 times.
|
891177 | if (cond_equal == nullptr) return true; |
| 4386 | 891177 | cond_equal->current_level.push_back(down_cast<Item_equal *>(cond)); | |
| 4387 | } | ||
| 4388 | } | ||
| 4389 |
2/2✓ Branch 0 taken 1860186 times.
✓ Branch 1 taken 305621 times.
|
2165807 | if (cond_equal) { |
| 4390 | 1860186 | cond_equal->upper_levels = inherited; | |
| 4391 | 1860186 | inherited = cond_equal; | |
| 4392 | } | ||
| 4393 | 2165807 | *cond_equal_ref = cond_equal; | |
| 4394 | |||
| 4395 |
2/2✓ Branch 0 taken 1767371 times.
✓ Branch 1 taken 398436 times.
|
2165807 | if (join_list) { |
| 4396 |
7/12✓ Branch 0 taken 1767370 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1767390 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3764314 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3764299 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5531678 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3764290 times.
✓ Branch 11 taken 1767388 times.
|
5531630 | for (TABLE_LIST *table : *join_list) { |
| 4397 |
2/2✓ Branch 0 taken 400295 times.
✓ Branch 1 taken 3363967 times.
|
3764314 | if (table->join_cond_optim()) { |
| 4398 | 400295 | mem_root_deque<TABLE_LIST *> *nested_join_list = | |
| 4399 |
2/2✓ Branch 0 taken 1859 times.
✓ Branch 1 taken 398436 times.
|
400295 | table->nested_join ? &table->nested_join->join_list : nullptr; |
| 4400 | Item *join_cond; | ||
| 4401 |
2/4✓ Branch 0 taken 400292 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 400292 times.
|
400295 | if (build_equal_items(thd, table->join_cond_optim(), &join_cond, |
| 4402 | inherited, do_inherit, nested_join_list, | ||
| 4403 | &table->cond_equal)) | ||
| 4404 | ✗ | return true; | |
| 4405 | 400292 | table->set_join_cond_optim(join_cond); | |
| 4406 | } | ||
| 4407 | } | ||
| 4408 | } | ||
| 4409 | |||
| 4410 | 2165824 | *retcond = cond; | |
| 4411 | 2165824 | return false; | |
| 4412 | } | ||
| 4413 | |||
| 4414 | /** | ||
| 4415 | Compare field items by table order in the execution plan. | ||
| 4416 | |||
| 4417 | field1 considered as better than field2 if the table containing | ||
| 4418 | field1 is accessed earlier than the table containing field2. | ||
| 4419 | The function finds out what of two fields is better according | ||
| 4420 | this criteria. | ||
| 4421 | |||
| 4422 | @param field1 first field item to compare | ||
| 4423 | @param field2 second field item to compare | ||
| 4424 | @param table_join_idx index to tables determining table order | ||
| 4425 | |||
| 4426 | @retval | ||
| 4427 | -1 if field1 is better than field2 | ||
| 4428 | @retval | ||
| 4429 | 1 if field2 is better than field1 | ||
| 4430 | @retval | ||
| 4431 | 0 otherwise | ||
| 4432 | */ | ||
| 4433 | |||
| 4434 | 2472480 | static int compare_fields_by_table_order(Item_field *field1, Item_field *field2, | |
| 4435 | JOIN_TAB **table_join_idx) { | ||
| 4436 | 2472480 | int cmp = 0; | |
| 4437 | 2472480 | bool outer_ref = false; | |
| 4438 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2472507 times.
|
2472480 | if (field1->is_outer_reference()) { |
| 4439 | ✗ | outer_ref = true; | |
| 4440 | ✗ | cmp = -1; | |
| 4441 | } | ||
| 4442 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2472506 times.
|
2472507 | if (field2->is_outer_reference()) { |
| 4443 | ✗ | outer_ref = true; | |
| 4444 | ✗ | cmp++; | |
| 4445 | } | ||
| 4446 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2472506 times.
|
2472506 | if (outer_ref) return cmp; |
| 4447 | |||
| 4448 | /* | ||
| 4449 | table_join_idx is NULL if this function was not called from JOIN::optimize() | ||
| 4450 | but from e.g. mysql_delete() or mysql_update(). In these cases | ||
| 4451 | there is only one table and both fields belong to it. Example | ||
| 4452 | condition where this is the case: t1.fld1=t1.fld2 | ||
| 4453 | */ | ||
| 4454 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 2472440 times.
|
2472506 | if (!table_join_idx) return 0; |
| 4455 | |||
| 4456 | // Locate JOIN_TABs thanks to table_join_idx, then compare their index. | ||
| 4457 | 2472440 | cmp = table_join_idx[field1->table_ref->tableno()]->idx() - | |
| 4458 | 2472434 | table_join_idx[field2->table_ref->tableno()]->idx(); | |
| 4459 |
4/4✓ Branch 0 taken 1253849 times.
✓ Branch 1 taken 1218587 times.
✓ Branch 2 taken 1253082 times.
✓ Branch 3 taken 767 times.
|
2472436 | return cmp < 0 ? -1 : (cmp ? 1 : 0); |
| 4460 | } | ||
| 4461 | |||
| 4462 | /** | ||
| 4463 | Generate minimal set of simple equalities equivalent to a multiple equality. | ||
| 4464 | |||
| 4465 | The function retrieves the fields of the multiple equality item | ||
| 4466 | item_equal and for each field f: | ||
| 4467 | - if item_equal contains const it generates the equality f=const_item; | ||
| 4468 | - otherwise, if f is not the first field, generates the equality | ||
| 4469 | f=item_equal->get_first(). | ||
| 4470 | All generated equality are added to the cond conjunction. | ||
| 4471 | |||
| 4472 | @param thd the session context | ||
| 4473 | @param cond condition to add the generated equality to | ||
| 4474 | @param upper_levels structure to access multiple equality of upper levels | ||
| 4475 | @param item_equal multiple equality to generate simple equality from | ||
| 4476 | |||
| 4477 | @note | ||
| 4478 | Before generating an equality function checks that it has not | ||
| 4479 | been generated for multiple equalities of the upper levels. | ||
| 4480 | E.g. for the following where condition | ||
| 4481 | WHERE a=5 AND ((a=b AND b=c) OR c>4) | ||
| 4482 | the upper level AND condition will contain =(5,a), | ||
| 4483 | while the lower level AND condition will contain =(5,a,b,c). | ||
| 4484 | When splitting =(5,a,b,c) into a separate equality predicates | ||
| 4485 | we should omit 5=a, as we have it already in the upper level. | ||
| 4486 | The following where condition gives us a more complicated case: | ||
| 4487 | WHERE t1.a=t2.b AND t3.c=t4.d AND (t2.b=t3.c OR t4.e>5 ...) AND ... | ||
| 4488 | Given the tables are accessed in the order t1->t2->t3->t4 for | ||
| 4489 | the selected query execution plan the lower level multiple | ||
| 4490 | equality =(t1.a,t2.b,t3.c,t4.d) formally should be converted to | ||
| 4491 | t1.a=t2.b AND t1.a=t3.c AND t1.a=t4.d. But t1.a=t2.a will be | ||
| 4492 | generated for the upper level. Also t3.c=t4.d will be generated there. | ||
| 4493 | So only t1.a=t3.c should be left in the lower level. | ||
| 4494 | If cond is equal to 0, then not more then one equality is generated | ||
| 4495 | and a pointer to it is returned as the result of the function. | ||
| 4496 | |||
| 4497 | @return | ||
| 4498 | - The condition with generated simple equalities or | ||
| 4499 | a pointer to the simple generated equality, if success. | ||
| 4500 | - 0, otherwise. | ||
| 4501 | */ | ||
| 4502 | |||
| 4503 | 5481119 | static Item *eliminate_item_equal(THD *thd, Item *cond, | |
| 4504 | COND_EQUAL *upper_levels, | ||
| 4505 | Item_equal *item_equal) { | ||
| 4506 | 5481119 | List<Item> eq_list; | |
| 4507 | 5481185 | Item *eq_item = nullptr; | |
| 4508 |
7/10✓ Branch 0 taken 5481213 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1702 times.
✓ Branch 3 taken 5479511 times.
✓ Branch 4 taken 1702 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1702 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1702 times.
✓ Branch 9 taken 5479511 times.
|
5481185 | if (((Item *)item_equal)->const_item() && !item_equal->val_int()) |
| 4509 |
1/2✓ Branch 0 taken 1702 times.
✗ Branch 1 not taken.
|
3404 | return new Item_func_false(); |
| 4510 | 5479511 | Item *const item_const = item_equal->get_const(); | |
| 4511 |
1/2✓ Branch 0 taken 5479428 times.
✗ Branch 1 not taken.
|
5479501 | auto it = item_equal->get_fields().begin(); |
| 4512 |
2/2✓ Branch 0 taken 1908851 times.
✓ Branch 1 taken 3570577 times.
|
5479428 | if (!item_const) { |
| 4513 | /* | ||
| 4514 | If there is a const item, match all field items with the const item, | ||
| 4515 | otherwise match the second and subsequent field items with the first one: | ||
| 4516 | */ | ||
| 4517 | 1908851 | it++; | |
| 4518 | } | ||
| 4519 |
4/6✓ Branch 0 taken 10998059 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10998036 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5518515 times.
✓ Branch 5 taken 5479521 times.
|
10998035 | while (it != item_equal->get_fields().end()) { |
| 4520 | /* | ||
| 4521 | Generate an equality of the form: | ||
| 4522 | item_field = some previous field in item_equal's list. | ||
| 4523 | |||
| 4524 | First see if we really need to generate it: | ||
| 4525 | */ | ||
| 4526 | 5518515 | Item_field *item_field = &*it++; // Field to generate equality for. | |
| 4527 |
1/2✓ Branch 0 taken 5518451 times.
✗ Branch 1 not taken.
|
5518490 | Item_equal *const upper = item_field->find_item_equal(upper_levels); |
| 4528 |
2/2✓ Branch 0 taken 114435 times.
✓ Branch 1 taken 5404016 times.
|
5518451 | if (upper) // item_field is in this upper equality |
| 4529 | { | ||
| 4530 |
6/6✓ Branch 0 taken 113907 times.
✓ Branch 1 taken 528 times.
✓ Branch 2 taken 113708 times.
✓ Branch 3 taken 201 times.
✓ Branch 4 taken 113710 times.
✓ Branch 5 taken 727 times.
|
114435 | if (item_const && upper->get_const()) |
| 4531 | 113710 | continue; // Const at both levels, no need to generate at current level | |
| 4532 | /* | ||
| 4533 | If the upper-level multiple equality contains this item, there is no | ||
| 4534 | need to generate the equality, unless item_field belongs to a | ||
| 4535 | semi-join nest that is used for Materialization, and refers to tables | ||
| 4536 | that are outside of the materialized semi-join nest, | ||
| 4537 | As noted in Item_equal::get_subst_item(), subquery materialization | ||
| 4538 | does not have this problem. | ||
| 4539 | */ | ||
| 4540 | 727 | JOIN_TAB *const tab = item_field->field->table->reginfo.join_tab; | |
| 4541 | |||
| 4542 |
6/8✓ Branch 0 taken 733 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 733 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 730 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 724 times.
✓ Branch 7 taken 3 times.
|
727 | if (!(tab && sj_is_materialize_strategy(tab->get_sj_strategy()))) { |
| 4543 | Item_field *item_match; | ||
| 4544 |
1/2✓ Branch 0 taken 724 times.
✗ Branch 1 not taken.
|
724 | auto li = item_equal->get_fields().begin(); |
| 4545 |
2/2✓ Branch 0 taken 623 times.
✓ Branch 1 taken 101 times.
|
724 | while ((item_match = &*li++) != item_field) { |
| 4546 |
2/4✓ Branch 0 taken 623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 623 times.
✗ Branch 3 not taken.
|
623 | if (item_match->find_item_equal(upper_levels) == upper) |
| 4547 | 623 | break; // (item_match, item_field) is also in upper level equality | |
| 4548 | } | ||
| 4549 |
2/2✓ Branch 0 taken 623 times.
✓ Branch 1 taken 101 times.
|
724 | if (item_match != item_field) continue; |
| 4550 | } | ||
| 4551 | } // ... if (upper). | ||
| 4552 | |||
| 4553 | /* | ||
| 4554 | item_field should be compared with the head of the multiple equality | ||
| 4555 | list. | ||
| 4556 | item_field may refer to a table that is within a semijoin materialization | ||
| 4557 | nest. In that case, the order of the join_tab entries may look like: | ||
| 4558 | |||
| 4559 | ot1 ot2 <subquery> ot5 SJM(it3 it4) | ||
| 4560 | |||
| 4561 | If we have a multiple equality | ||
| 4562 | |||
| 4563 | (ot1.c1, ot2.c2, <subquery>.c it3.c3, it4.c4, ot5.c5), | ||
| 4564 | |||
| 4565 | we should generate the following equalities: | ||
| 4566 | 1. ot1.c1 = ot2.c2 | ||
| 4567 | 2. ot1.c1 = <subquery>.c | ||
| 4568 | 3. it3.c3 = it4.c4 | ||
| 4569 | 4. ot1.c1 = ot5.c5 | ||
| 4570 | |||
| 4571 | Equalities 1) and 4) are regular equalities between two outer tables. | ||
| 4572 | Equality 2) is an equality that matches the outer query with a | ||
| 4573 | materialized temporary table. It is either performed as a lookup | ||
| 4574 | into the materialized table (SJM-lookup), or as a condition on the | ||
| 4575 | outer table (SJM-scan). | ||
| 4576 | Equality 3) is evaluated during semijoin materialization. | ||
| 4577 | |||
| 4578 | If there is a const item, match against this one. | ||
| 4579 | Otherwise, match against the first field item in the multiple equality, | ||
| 4580 | unless the item is within a materialized semijoin nest, in case it will | ||
| 4581 | be matched against the first item within the SJM nest. | ||
| 4582 | @see JOIN::set_prefix_tables() | ||
| 4583 | @see Item_equal::get_subst_item() | ||
| 4584 | */ | ||
| 4585 | |||
| 4586 | Item *const head = | ||
| 4587 |
3/4✓ Branch 0 taken 1931004 times.
✓ Branch 1 taken 3473116 times.
✓ Branch 2 taken 1931002 times.
✗ Branch 3 not taken.
|
5404120 | item_const ? item_const : item_equal->get_subst_item(item_field); |
| 4588 |
2/2✓ Branch 0 taken 176 times.
✓ Branch 1 taken 5403942 times.
|
5404118 | if (head == item_field) continue; |
| 4589 | |||
| 4590 | // we have a pair, can generate 'item_field=head' | ||
| 4591 |
3/4✓ Branch 0 taken 23184 times.
✓ Branch 1 taken 5380758 times.
✓ Branch 2 taken 23184 times.
✗ Branch 3 not taken.
|
5403942 | if (eq_item) eq_list.push_back(eq_item); |
| 4592 | |||
| 4593 |
3/4✓ Branch 0 taken 5403955 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1931145 times.
✓ Branch 3 taken 3472810 times.
|
5403942 | if (head->type() == Item::FIELD_ITEM) { |
| 4594 | // Store away all fields that were considered equal, so that we are able | ||
| 4595 | // to undo this operation later if we have to. See | ||
| 4596 | // Item_func::ensure_multi_equality_fields_are_available for more details. | ||
| 4597 | 1931145 | Item_field *head_field = down_cast<Item_field *>(head); | |
| 4598 | 1931143 | head_field->set_item_equal_all_join_nests(item_equal); | |
| 4599 | } | ||
| 4600 |
2/4✓ Branch 0 taken 5404029 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5404021 times.
✗ Branch 3 not taken.
|
5403947 | eq_item = new Item_func_eq(item_field, head); |
| 4601 | |||
| 4602 |
6/8✓ Branch 0 taken 5404031 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5404039 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 5404028 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 5404028 times.
|
5404021 | if (!eq_item || down_cast<Item_func_eq *>(eq_item)->set_cmp_func()) |
| 4603 | 1 | return nullptr; | |
| 4604 | |||
| 4605 | 5404028 | eq_item->quick_fix_field(); | |
| 4606 |
2/2✓ Branch 0 taken 3473132 times.
✓ Branch 1 taken 1930845 times.
|
5403977 | if (item_const != nullptr) { |
| 4607 |
1/2✓ Branch 0 taken 3473155 times.
✗ Branch 1 not taken.
|
3473132 | eq_item->apply_is_true(); |
| 4608 | Item::cond_result res; | ||
| 4609 |
2/4✓ Branch 0 taken 3473249 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3473249 times.
|
3473155 | if (fold_condition(thd, eq_item, &eq_item, &res)) return nullptr; |
| 4610 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3473249 times.
|
3473249 | if (res == Item::COND_FALSE) { |
| 4611 | ✗ | eq_item = new (thd->mem_root) Item_func_false(); | |
| 4612 | ✗ | if (eq_item == nullptr) return nullptr; | |
| 4613 | ✗ | return eq_item; // entire AND is false | |
| 4614 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3473249 times.
|
3473249 | } else if (res == Item::COND_TRUE) { |
| 4615 | ✗ | eq_item = new (thd->mem_root) Item_func_true(); | |
| 4616 | ✗ | if (eq_item == nullptr) return nullptr; | |
| 4617 | } | ||
| 4618 | } | ||
| 4619 | } // ... while ((item_field= it++)) | ||
| 4620 | |||
| 4621 |
6/6✓ Branch 0 taken 893503 times.
✓ Branch 1 taken 4586018 times.
✓ Branch 2 taken 891696 times.
✓ Branch 3 taken 1795 times.
✓ Branch 4 taken 891700 times.
✓ Branch 5 taken 4587809 times.
|
5479521 | if (!cond && !eq_list.head()) { |
| 4622 |
3/4✓ Branch 0 taken 65441 times.
✓ Branch 1 taken 826259 times.
✓ Branch 2 taken 65441 times.
✗ Branch 3 not taken.
|
957141 | if (!eq_item) return new Item_func_true(); |
| 4623 | 826259 | return eq_item; | |
| 4624 | } | ||
| 4625 | |||
| 4626 |
3/4✓ Branch 0 taken 4554627 times.
✓ Branch 1 taken 33182 times.
✓ Branch 2 taken 4554627 times.
✗ Branch 3 not taken.
|
4587809 | if (eq_item) eq_list.push_back(eq_item); |
| 4627 |
2/2✓ Branch 0 taken 1798 times.
✓ Branch 1 taken 4586011 times.
|
4587809 | if (!cond) |
| 4628 |
2/4✓ Branch 0 taken 1798 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1798 times.
✗ Branch 3 not taken.
|
1798 | cond = new Item_cond_and(eq_list); |
| 4629 | else { | ||
| 4630 |
2/4✓ Branch 0 taken 4586010 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4586010 times.
|
4586011 | assert(cond->type() == Item::COND_ITEM); |
| 4631 |
3/4✓ Branch 0 taken 4552820 times.
✓ Branch 1 taken 33190 times.
✓ Branch 2 taken 4552825 times.
✗ Branch 3 not taken.
|
4586010 | if (eq_list.elements) ((Item_cond *)cond)->add_at_head(&eq_list); |
| 4632 | } | ||
| 4633 | |||
| 4634 | 4587813 | cond->quick_fix_field(); | |
| 4635 |
1/2✓ Branch 0 taken 4587816 times.
✗ Branch 1 not taken.
|
4587812 | cond->update_used_tables(); |
| 4636 | |||
| 4637 | 4587816 | return cond; | |
| 4638 | } | ||
| 4639 | |||
| 4640 | /** | ||
| 4641 | Substitute every field reference in a condition by the best equal field | ||
| 4642 | and eliminate all multiple equality predicates. | ||
| 4643 | |||
| 4644 | The function retrieves the cond condition and for each encountered | ||
| 4645 | multiple equality predicate it sorts the field references in it | ||
| 4646 | according to the order of tables specified by the table_join_idx | ||
| 4647 | parameter. Then it eliminates the multiple equality predicate by | ||
| 4648 | replacing it with the conjunction of simple equality predicates | ||
| 4649 | equating every field from the multiple equality to the first | ||
| 4650 | field in it, or to the constant, if there is any. | ||
| 4651 | After this, the function retrieves all other conjuncted | ||
| 4652 | predicates and substitutes every field reference by the field reference | ||
| 4653 | to the first equal field or equal constant if there are any. | ||
| 4654 | |||
| 4655 | @param thd the session context | ||
| 4656 | @param cond condition to process | ||
| 4657 | @param cond_equal multiple equalities to take into consideration | ||
| 4658 | @param table_join_idx index to tables determining field preference | ||
| 4659 | |||
| 4660 | @note | ||
| 4661 | At the first glance, a full sort of fields in multiple equality | ||
| 4662 | seems to be an overkill. Yet it's not the case due to possible | ||
| 4663 | new fields in multiple equality item of lower levels. We want | ||
| 4664 | the order in them to comply with the order of upper levels. | ||
| 4665 | |||
| 4666 | @return | ||
| 4667 | The transformed condition, or NULL in case of error | ||
| 4668 | */ | ||
| 4669 | |||
| 4670 | 4652902 | Item *substitute_for_best_equal_field(THD *thd, Item *cond, | |
| 4671 | COND_EQUAL *cond_equal, | ||
| 4672 | JOIN_TAB **table_join_idx) { | ||
| 4673 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4652977 times.
|
4652902 | assert(cond->is_bool_func()); |
| 4674 |
2/2✓ Branch 0 taken 1939534 times.
✓ Branch 1 taken 2713447 times.
|
4652977 | if (cond->type() == Item::COND_ITEM) { |
| 4675 | 1939534 | List<Item> *cond_list = ((Item_cond *)cond)->argument_list(); | |
| 4676 | |||
| 4677 | bool and_level = | ||
| 4678 |
1/2✓ Branch 0 taken 1939530 times.
✗ Branch 1 not taken.
|
1939534 | ((Item_cond *)cond)->functype() == Item_func::COND_AND_FUNC; |
| 4679 |
2/2✓ Branch 0 taken 1919232 times.
✓ Branch 1 taken 20298 times.
|
1939530 | if (and_level) { |
| 4680 | 1919232 | cond_equal = &((Item_cond_and *)cond)->cond_equal; | |
| 4681 | 1919232 | cond_list->disjoin((List<Item> *)&cond_equal->current_level); | |
| 4682 | |||
| 4683 |
1/2✓ Branch 0 taken 1919233 times.
✗ Branch 1 not taken.
|
1919231 | List_iterator_fast<Item_equal> it(cond_equal->current_level); |
| 4684 | 1737949 | auto cmp = [table_join_idx](Item_field *f1, Item_field *f2) { | |
| 4685 | 1737949 | return compare_fields_by_table_order(f1, f2, table_join_idx); | |
| 4686 | 1919233 | }; | |
| 4687 | Item_equal *item_equal; | ||
| 4688 |
2/2✓ Branch 0 taken 4587599 times.
✓ Branch 1 taken 1919237 times.
|
6506824 | while ((item_equal = it++)) { |
| 4689 |
1/2✓ Branch 0 taken 4587591 times.
✗ Branch 1 not taken.
|
4587599 | item_equal->sort(cmp); |
| 4690 | } | ||
| 4691 | } | ||
| 4692 | |||
| 4693 |
1/2✓ Branch 0 taken 1939533 times.
✗ Branch 1 not taken.
|
1939535 | List_iterator<Item> li(*cond_list); |
| 4694 | Item *item; | ||
| 4695 |
2/2✓ Branch 0 taken 2511113 times.
✓ Branch 1 taken 1939535 times.
|
4450647 | while ((item = li++)) { |
| 4696 |
1/2✓ Branch 0 taken 2511114 times.
✗ Branch 1 not taken.
|
2511113 | Item *new_item = substitute_for_best_equal_field(thd, item, cond_equal, |
| 4697 | table_join_idx); | ||
| 4698 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2511114 times.
|
2511114 | if (new_item == nullptr) return nullptr; |
| 4699 | /* | ||
| 4700 | This works OK with PS/SP re-execution as changes are made to | ||
| 4701 | the arguments of AND/OR items only | ||
| 4702 | */ | ||
| 4703 |
2/2✓ Branch 0 taken 10534 times.
✓ Branch 1 taken 2500580 times.
|
2511114 | if (new_item != item) li.replace(new_item); |
| 4704 | } | ||
| 4705 | |||
| 4706 |
2/2✓ Branch 0 taken 1919236 times.
✓ Branch 1 taken 20299 times.
|
1939535 | if (and_level) { |
| 4707 |
1/2✓ Branch 0 taken 1919235 times.
✗ Branch 1 not taken.
|
1919236 | List_iterator_fast<Item_equal> it(cond_equal->current_level); |
| 4708 | Item_equal *item_equal; | ||
| 4709 |
2/2✓ Branch 0 taken 4587550 times.
✓ Branch 1 taken 1917699 times.
|
6505253 | while ((item_equal = it++)) { |
| 4710 |
1/2✓ Branch 0 taken 4587556 times.
✗ Branch 1 not taken.
|
4587550 | cond = eliminate_item_equal(thd, cond, cond_equal->upper_levels, |
| 4711 | item_equal); | ||
| 4712 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4587556 times.
|
4587556 | if (cond == nullptr) return nullptr; |
| 4713 | // This occurs when eliminate_item_equal() founds that cond is | ||
| 4714 | // always false and substitutes it with a false value. | ||
| 4715 | // Due to this, value of item_equal will be 0, so just return it. | ||
| 4716 |
3/4✓ Branch 0 taken 4587556 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1538 times.
✓ Branch 3 taken 4586018 times.
|
4587556 | if (cond->type() != Item::COND_ITEM) break; |
| 4717 | } | ||
| 4718 | } | ||
| 4719 |
5/6✓ Branch 0 taken 1939539 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1938001 times.
✓ Branch 3 taken 1538 times.
✓ Branch 4 taken 13972 times.
✓ Branch 5 taken 1925567 times.
|
3877537 | if (cond->type() == Item::COND_ITEM && |
| 4720 |
2/2✓ Branch 0 taken 13972 times.
✓ Branch 1 taken 1924029 times.
|
1938001 | !((Item_cond *)cond)->argument_list()->elements) |
| 4721 |
3/6✓ Branch 0 taken 13972 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13972 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13972 times.
✗ Branch 5 not taken.
|
27944 | cond = cond->val_bool() ? implicit_cast<Item *>(new Item_func_true()) |
| 4722 | ✗ | : implicit_cast<Item *>(new Item_func_false()); | |
| 4723 |
4/4✓ Branch 0 taken 2713338 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 893646 times.
✓ Branch 3 taken 1819799 times.
|
5426865 | } else if (cond->type() == Item::FUNC_ITEM && |
| 4724 |
2/2✓ Branch 0 taken 893647 times.
✓ Branch 1 taken 1819771 times.
|
2713338 | (down_cast<Item_func *>(cond))->functype() == |
| 4725 | Item_func::MULT_EQUAL_FUNC) { | ||
| 4726 | 893646 | Item_equal *item_equal = down_cast<Item_equal *>(cond); | |
| 4727 | 893657 | item_equal->sort([table_join_idx](Item_field *f1, Item_field *f2) { | |
| 4728 | 734538 | return compare_fields_by_table_order(f1, f2, table_join_idx); | |
| 4729 | }); | ||
| 4730 |
6/6✓ Branch 0 taken 888012 times.
✓ Branch 1 taken 5581 times.
✓ Branch 2 taken 882340 times.
✓ Branch 3 taken 5725 times.
✓ Branch 4 taken 882298 times.
✓ Branch 5 taken 11348 times.
|
893593 | if (cond_equal && cond_equal->current_level.head() == item_equal) |
| 4731 | 882298 | cond_equal = cond_equal->upper_levels; | |
| 4732 | 893646 | return eliminate_item_equal(thd, nullptr, cond_equal, item_equal); | |
| 4733 | } else { | ||
| 4734 | 1819799 | uchar *dummy = nullptr; | |
| 4735 |
1/2✓ Branch 0 taken 1819796 times.
✗ Branch 1 not taken.
|
1819799 | if (cond->compile(&Item::visit_all_analyzer, &dummy, |
| 4736 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1819796 times.
|
1819796 | &Item::replace_equal_field, nullptr) == nullptr) |
| 4737 | ✗ | return nullptr; | |
| 4738 | } | ||
| 4739 | 3759335 | return cond; | |
| 4740 | } | ||
| 4741 | |||
| 4742 | /** | ||
| 4743 | change field = field to field = const for each found field = const in the | ||
| 4744 | and_level | ||
| 4745 | |||
| 4746 | @param thd Thread handler | ||
| 4747 | @param save_list saved list of COND_CMP | ||
| 4748 | @param and_father father of AND op | ||
| 4749 | @param cond Condition where fields are replaced with constant values | ||
| 4750 | @param field The field that will be substituted | ||
| 4751 | @param value The substitution value | ||
| 4752 | |||
| 4753 | @returns false if success, true if error | ||
| 4754 | */ | ||
| 4755 | |||
| 4756 | 549863 | static bool change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list, | |
| 4757 | Item *and_father, Item *cond, Item *field, | ||
| 4758 | Item *value) { | ||
| 4759 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 549863 times.
|
549863 | assert(cond->real_item()->is_bool_func()); |
| 4760 |
2/2✓ Branch 0 taken 151165 times.
✓ Branch 1 taken 398698 times.
|
549863 | if (cond->type() == Item::COND_ITEM) { |
| 4761 | 151165 | Item_cond *const item_cond = down_cast<Item_cond *>(cond); | |
| 4762 |
1/2✓ Branch 0 taken 151165 times.
✗ Branch 1 not taken.
|
151165 | bool and_level = item_cond->functype() == Item_func::COND_AND_FUNC; |
| 4763 |
1/2✓ Branch 0 taken 151165 times.
✗ Branch 1 not taken.
|
151165 | List_iterator<Item> li(*item_cond->argument_list()); |
| 4764 | Item *item; | ||
| 4765 |
2/2✓ Branch 0 taken 399107 times.
✓ Branch 1 taken 151165 times.
|
550272 | while ((item = li++)) { |
| 4766 |
4/6✓ Branch 0 taken 398302 times.
✓ Branch 1 taken 805 times.
✓ Branch 2 taken 399107 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 399107 times.
|
399107 | if (change_cond_ref_to_const(thd, save_list, and_level ? cond : item, |
| 4767 | item, field, value)) | ||
| 4768 | ✗ | return true; | |
| 4769 | } | ||
| 4770 | 151165 | return false; | |
| 4771 | } | ||
| 4772 |
2/2✓ Branch 0 taken 141160 times.
✓ Branch 1 taken 257538 times.
|
398698 | if (cond->eq_cmp_result() == Item::COND_OK) |
| 4773 | 141160 | return false; // Not a boolean function | |
| 4774 | |||
| 4775 | 257538 | Item_bool_func2 *func = down_cast<Item_bool_func2 *>(cond); | |
| 4776 | 257538 | Item **args = func->arguments(); | |
| 4777 | 257538 | Item *left_item = args[0]; | |
| 4778 | 257538 | Item *right_item = args[1]; | |
| 4779 | 257538 | Item_func::Functype functype = func->functype(); | |
| 4780 | |||
| 4781 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 88 times.
|
257649 | if (right_item->eq(field, false) && left_item != value && |
| 4782 |
5/6✓ Branch 0 taken 111 times.
✓ Branch 1 taken 257427 times.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 257515 times.
|
257672 | right_item->cmp_context == field->cmp_context && |
| 4783 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 8 times.
|
23 | (left_item->result_type() != STRING_RESULT || |
| 4784 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | value->result_type() != STRING_RESULT || |
| 4785 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | left_item->collation.collation == value->collation.collation)) { |
| 4786 | 23 | Item *const clone = value->clone_item(); | |
| 4787 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (thd->is_error()) return true; |
| 4788 | |||
| 4789 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 21 times.
|
23 | if (clone == nullptr) return false; |
| 4790 | |||
| 4791 | 21 | clone->collation.set(right_item->collation); | |
| 4792 | 21 | thd->change_item_tree(args + 1, clone); | |
| 4793 | 21 | func->update_used_tables(); | |
| 4794 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
21 | if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC) && |
| 4795 |
5/6✓ Branch 0 taken 10 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 10 times.
|
42 | and_father != cond && !left_item->const_item()) { |
| 4796 | 11 | cond->marker = Item::MARKER_CONST_PROPAG; | |
| 4797 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | COND_CMP *const cond_cmp = new COND_CMP(and_father, func); |
| 4798 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (cond_cmp == nullptr) return true; |
| 4799 | |||
| 4800 | 11 | save_list->push_back(cond_cmp); | |
| 4801 | } | ||
| 4802 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (func->set_cmp_func()) return true; |
| 4803 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 150652 times.
|
408207 | } else if (left_item->eq(field, false) && right_item != value && |
| 4804 |
5/6✓ Branch 0 taken 150692 times.
✓ Branch 1 taken 106823 times.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✓ Branch 5 taken 257478 times.
|
408247 | left_item->cmp_context == field->cmp_context && |
| 4805 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 9 times.
|
40 | (right_item->result_type() != STRING_RESULT || |
| 4806 |
1/2✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
|
31 | value->result_type() != STRING_RESULT || |
| 4807 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 3 times.
|
31 | right_item->collation.collation == value->collation.collation)) { |
| 4808 | 37 | Item *const clone = value->clone_item(); | |
| 4809 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (thd->is_error()) return true; |
| 4810 | |||
| 4811 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (clone == nullptr) return false; |
| 4812 | |||
| 4813 | 37 | clone->collation.set(left_item->collation); | |
| 4814 | 37 | thd->change_item_tree(args, clone); | |
| 4815 | 37 | value = clone; | |
| 4816 | 37 | func->update_used_tables(); | |
| 4817 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
37 | if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC) && |
| 4818 |
6/6✓ Branch 0 taken 21 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 24 times.
|
74 | and_father != cond && !right_item->const_item()) { |
| 4819 | 13 | args[0] = args[1]; // For easy check | |
| 4820 | 13 | thd->change_item_tree(args + 1, value); | |
| 4821 | 13 | cond->marker = Item::MARKER_CONST_PROPAG; | |
| 4822 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | COND_CMP *const cond_cmp = new COND_CMP(and_father, func); |
| 4823 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (cond_cmp == nullptr) return true; |
| 4824 | |||
| 4825 | 13 | save_list->push_back(cond_cmp); | |
| 4826 | } | ||
| 4827 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (func->set_cmp_func()) return true; |
| 4828 | } | ||
| 4829 | 257536 | return false; | |
| 4830 | } | ||
| 4831 | |||
| 4832 | /** | ||
| 4833 | Propagate constant values in a condition | ||
| 4834 | |||
| 4835 | @param thd Thread handler | ||
| 4836 | @param save_list saved list of COND_CMP | ||
| 4837 | @param and_father father of AND op | ||
| 4838 | @param cond Condition for which constant values are propagated | ||
| 4839 | |||
| 4840 | @returns false if success, true if error | ||
| 4841 | */ | ||
| 4842 | 8674258 | static bool propagate_cond_constants(THD *thd, I_List<COND_CMP> *save_list, | |
| 4843 | Item *and_father, Item *cond) { | ||
| 4844 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8674271 times.
|
8674258 | assert(cond->real_item()->is_bool_func()); |
| 4845 |
2/2✓ Branch 0 taken 1846467 times.
✓ Branch 1 taken 6827831 times.
|
8674271 | if (cond->type() == Item::COND_ITEM) { |
| 4846 | 1846467 | Item_cond *const item_cond = down_cast<Item_cond *>(cond); | |
| 4847 |
1/2✓ Branch 0 taken 1846409 times.
✗ Branch 1 not taken.
|
1846411 | bool and_level = item_cond->functype() == Item_func::COND_AND_FUNC; |
| 4848 |
1/2✓ Branch 0 taken 1846411 times.
✗ Branch 1 not taken.
|
1846409 | List_iterator_fast<Item> li(*item_cond->argument_list()); |
| 4849 | Item *item; | ||
| 4850 |
1/2✓ Branch 0 taken 1846405 times.
✗ Branch 1 not taken.
|
1846411 | I_List<COND_CMP> save; |
| 4851 |
2/2✓ Branch 0 taken 6908816 times.
✓ Branch 1 taken 1846409 times.
|
8755223 | while ((item = li++)) { |
| 4852 |
5/6✓ Branch 0 taken 5889289 times.
✓ Branch 1 taken 1019527 times.
✓ Branch 2 taken 6908819 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 6908818 times.
|
6908816 | if (propagate_cond_constants(thd, &save, and_level ? cond : item, item)) |
| 4853 | 1 | return true; | |
| 4854 | } | ||
| 4855 |
2/2✓ Branch 0 taken 1816763 times.
✓ Branch 1 taken 29646 times.
|
1846409 | if (and_level) { // Handle other found items |
| 4856 |
1/2✓ Branch 0 taken 1816763 times.
✗ Branch 1 not taken.
|
1816763 | I_List_iterator<COND_CMP> cond_itr(save); |
| 4857 | COND_CMP *cond_cmp; | ||
| 4858 |
3/4✓ Branch 0 taken 1816785 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 1816761 times.
|
1816787 | while ((cond_cmp = cond_itr++)) { |
| 4859 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | Item **args = cond_cmp->cmp_func->arguments(); |
| 4860 |
3/6✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
|
48 | if (!args[0]->const_item() && |
| 4861 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | change_cond_ref_to_const(thd, &save, cond_cmp->and_level, |
| 4862 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | cond_cmp->and_level, args[0], args[1])) |
| 4863 | ✗ | return true; | |
| 4864 | } | ||
| 4865 | } | ||
| 4866 |
2/2✓ Branch 0 taken 5883786 times.
✓ Branch 1 taken 944045 times.
|
6827831 | } else if (and_father != cond && |
| 4867 |
2/2✓ Branch 0 taken 5883779 times.
✓ Branch 1 taken 7 times.
|
5883786 | cond->marker != Item::MARKER_CONST_PROPAG) // In a AND group |
| 4868 | { | ||
| 4869 | Item_func *func; | ||
| 4870 |
1/2✓ Branch 0 taken 5883728 times.
✗ Branch 1 not taken.
|
11767506 | if (cond->type() == Item::FUNC_ITEM && |
| 4871 |
4/4✓ Branch 0 taken 5883727 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 175749 times.
✓ Branch 3 taken 5708033 times.
|
11767509 | (func = down_cast<Item_func *>(cond)) && |
| 4872 |
2/2✓ Branch 0 taken 5708105 times.
✓ Branch 1 taken 175619 times.
|
5883728 | (func->functype() == Item_func::EQ_FUNC || |
| 4873 |
2/2✓ Branch 0 taken 130 times.
✓ Branch 1 taken 5707984 times.
|
5708105 | func->functype() == Item_func::EQUAL_FUNC)) { |
| 4874 | 175749 | Item **args = func->arguments(); | |
| 4875 | 175749 | bool left_const = args[0]->const_item(); | |
| 4876 | 175749 | bool right_const = args[1]->const_item(); | |
| 4877 |
6/6✓ Branch 0 taken 199 times.
✓ Branch 1 taken 175550 times.
✓ Branch 2 taken 97 times.
✓ Branch 3 taken 102 times.
✓ Branch 4 taken 171045 times.
✓ Branch 5 taken 4704 times.
|
351396 | if (!(left_const && right_const) && |
| 4878 |
2/2✓ Branch 0 taken 171045 times.
✓ Branch 1 taken 4602 times.
|
175647 | args[0]->result_type() == args[1]->result_type()) { |
| 4879 |
2/2✓ Branch 0 taken 150639 times.
✓ Branch 1 taken 20406 times.
|
171045 | if (right_const) { |
| 4880 | 150639 | Item *item = args[1]; | |
| 4881 |
3/4✓ Branch 0 taken 150639 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 150638 times.
|
150639 | if (resolve_const_item(thd, &item, args[0])) return true; |
| 4882 |
1/2✓ Branch 0 taken 150638 times.
✗ Branch 1 not taken.
|
150638 | thd->change_item_tree(&args[1], item); |
| 4883 |
1/2✓ Branch 0 taken 150638 times.
✗ Branch 1 not taken.
|
150638 | func->update_used_tables(); |
| 4884 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 150638 times.
|
150638 | if (change_cond_ref_to_const(thd, save_list, and_father, and_father, |
| 4885 |
1/2✓ Branch 0 taken 150638 times.
✗ Branch 1 not taken.
|
150638 | args[0], args[1])) |
| 4886 | ✗ | return true; | |
| 4887 |
2/2✓ Branch 0 taken 94 times.
✓ Branch 1 taken 20312 times.
|
20406 | } else if (left_const) { |
| 4888 | 94 | Item *item = args[0]; | |
| 4889 |
2/4✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 94 times.
|
94 | if (resolve_const_item(thd, &item, args[1])) return true; |
| 4890 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
94 | thd->change_item_tree(&args[0], item); |
| 4891 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
94 | func->update_used_tables(); |
| 4892 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
94 | if (change_cond_ref_to_const(thd, save_list, and_father, and_father, |
| 4893 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
94 | args[1], args[0])) |
| 4894 | ✗ | return true; | |
| 4895 | } | ||
| 4896 | } | ||
| 4897 | } | ||
| 4898 | } | ||
| 4899 | |||
| 4900 | 8674240 | return false; | |
| 4901 | } | ||
| 4902 | |||
| 4903 | /** | ||
| 4904 | Assign each nested join structure a bit in nested_join_map. | ||
| 4905 | |||
| 4906 | @param join_list List of tables | ||
| 4907 | @param first_unused Number of first unused bit in nested_join_map before the | ||
| 4908 | call | ||
| 4909 | |||
| 4910 | @note | ||
| 4911 | This function is called after simplify_joins(), when there are no | ||
| 4912 | redundant nested joins. | ||
| 4913 | We cannot have more nested joins in a query block than there are tables, | ||
| 4914 | so as long as the number of bits in nested_join_map is not less than the | ||
| 4915 | maximum number of tables in a query block, nested_join_map can never | ||
| 4916 | overflow. | ||
| 4917 | |||
| 4918 | @return | ||
| 4919 | First unused bit in nested_join_map after the call. | ||
| 4920 | */ | ||
| 4921 | |||
| 4922 | 19043662 | uint build_bitmap_for_nested_joins(mem_root_deque<TABLE_LIST *> *join_list, | |
| 4923 | uint first_unused) { | ||
| 4924 |
1/2✓ Branch 0 taken 19044655 times.
✗ Branch 1 not taken.
|
19043662 | DBUG_TRACE; |
| 4925 |
7/12✓ Branch 0 taken 19044678 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19044847 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3984829 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3984831 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 23028939 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3984824 times.
✓ Branch 11 taken 19044115 times.
|
23029484 | for (TABLE_LIST *table : *join_list) { |
| 4926 | NESTED_JOIN *nested_join; | ||
| 4927 |
2/2✓ Branch 0 taken 6262 times.
✓ Branch 1 taken 3978567 times.
|
3984829 | if ((nested_join = table->nested_join)) { |
| 4928 | // We should have a join condition or a semi-join condition or both | ||
| 4929 |
3/4✓ Branch 0 taken 4433 times.
✓ Branch 1 taken 1829 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4433 times.
|
6262 | assert((table->join_cond() != nullptr) || table->is_sj_nest()); |
| 4930 | |||
| 4931 | 6262 | nested_join->nj_map = 0; | |
| 4932 | 6262 | nested_join->nj_total = 0; | |
| 4933 | /* | ||
| 4934 | We only record nested join information for outer join nests. | ||
| 4935 | Tables belonging in semi-join nests are recorded in the | ||
| 4936 | embedding outer join nest, if one exists. | ||
| 4937 | */ | ||
| 4938 |
2/2✓ Branch 0 taken 1829 times.
✓ Branch 1 taken 4433 times.
|
6262 | if (table->join_cond()) { |
| 4939 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1829 times.
|
1829 | assert(first_unused < sizeof(nested_join_map) * 8); |
| 4940 | 1829 | nested_join->nj_map = (nested_join_map)1 << first_unused++; | |
| 4941 | 1829 | nested_join->nj_total = nested_join->join_list.size(); | |
| 4942 |
1/2✓ Branch 0 taken 4433 times.
✗ Branch 1 not taken.
|
4433 | } else if (table->is_sj_nest()) { |
| 4943 | 4433 | NESTED_JOIN *const outer_nest = | |
| 4944 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 4408 times.
|
4433 | table->embedding ? table->embedding->nested_join : nullptr; |
| 4945 | /* | ||
| 4946 | The semi-join nest has already been counted into the table count | ||
| 4947 | for the outer join nest as one table, so subtract 1 from the | ||
| 4948 | table count. | ||
| 4949 | */ | ||
| 4950 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 4408 times.
|
4433 | if (outer_nest) |
| 4951 | 25 | outer_nest->nj_total += (nested_join->join_list.size() - 1); | |
| 4952 | } else | ||
| 4953 | ✗ | assert(false); | |
| 4954 | |||
| 4955 | first_unused = | ||
| 4956 |
1/2✓ Branch 0 taken 6262 times.
✗ Branch 1 not taken.
|
6262 | build_bitmap_for_nested_joins(&nested_join->join_list, first_unused); |
| 4957 | } | ||
| 4958 | } | ||
| 4959 | 19044744 | return first_unused; | |
| 4960 | 19044115 | } | |
| 4961 | |||
| 4962 | /** Update the dependency map for the tables. */ | ||
| 4963 | |||
| 4964 | 1903441 | void JOIN::update_depend_map() { | |
| 4965 |
3/6✓ Branch 0 taken 1903442 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1903444 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1903452 times.
✗ Branch 5 not taken.
|
1903441 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 4966 |
2/2✓ Branch 0 taken 6477201 times.
✓ Branch 1 taken 1903469 times.
|
8380670 | for (uint tableno = 0; tableno < tables; tableno++) { |
| 4967 | 6477201 | JOIN_TAB *const tab = best_ref[tableno]; | |
| 4968 | 6477201 | TABLE_REF *const ref = &tab->ref(); | |
| 4969 | 6477217 | table_map depend_map = 0; | |
| 4970 | 6477217 | Item **item = ref->items; | |
| 4971 |
2/2✓ Branch 0 taken 2743437 times.
✓ Branch 1 taken 6477219 times.
|
9220656 | for (uint i = 0; i < ref->key_parts; i++, item++) |
| 4972 | 2743437 | depend_map |= (*item)->used_tables(); | |
| 4973 | 6477219 | depend_map &= ~PSEUDO_TABLE_BITS; | |
| 4974 | 6477219 | ref->depend_map = depend_map; | |
| 4975 |
2/2✓ Branch 0 taken 3871789 times.
✓ Branch 1 taken 6477219 times.
|
10349008 | for (JOIN_TAB **tab2 = map2table; depend_map; tab2++, depend_map >>= 1) { |
| 4976 |
2/2✓ Branch 0 taken 1812553 times.
✓ Branch 1 taken 2059236 times.
|
3871789 | if (depend_map & 1) ref->depend_map |= (*tab2)->ref().depend_map; |
| 4977 | } | ||
| 4978 | } | ||
| 4979 | 1903469 | } | |
| 4980 | |||
| 4981 | /** Update the dependency map for the sort order. */ | ||
| 4982 | |||
| 4983 | 3627771 | void JOIN::update_depend_map(ORDER *order) { | |
| 4984 |
1/2✓ Branch 0 taken 3627791 times.
✗ Branch 1 not taken.
|
3627771 | DBUG_TRACE; |
| 4985 |
2/2✓ Branch 0 taken 1023214 times.
✓ Branch 1 taken 3627793 times.
|
4651007 | for (; order; order = order->next) { |
| 4986 | table_map depend_map; | ||
| 4987 |
1/2✓ Branch 0 taken 1023214 times.
✗ Branch 1 not taken.
|
1023214 | order->item[0]->update_used_tables(); |
| 4988 | 1023216 | order->depend_map = depend_map = | |
| 4989 |
1/2✓ Branch 0 taken 1023216 times.
✗ Branch 1 not taken.
|
1023214 | order->item[0]->used_tables() & ~INNER_TABLE_BIT; |
| 4990 | 1023216 | order->used = 0; | |
| 4991 | // Not item_sum(), RAND() and no reference to table outside of sub select | ||
| 4992 |
4/4✓ Branch 0 taken 1021838 times.
✓ Branch 1 taken 1378 times.
✓ Branch 2 taken 1021524 times.
✓ Branch 3 taken 1692 times.
|
2045054 | if (!(order->depend_map & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT)) && |
| 4993 |
2/2✓ Branch 0 taken 1021524 times.
✓ Branch 1 taken 314 times.
|
1021838 | !order->item[0]->has_aggregation()) { |
| 4994 |
2/2✓ Branch 0 taken 1343055 times.
✓ Branch 1 taken 1021524 times.
|
2364579 | for (JOIN_TAB **tab = map2table; depend_map; tab++, depend_map >>= 1) { |
| 4995 |
2/2✓ Branch 0 taken 1079315 times.
✓ Branch 1 taken 263740 times.
|
1343055 | if (depend_map & 1) order->depend_map |= (*tab)->ref().depend_map; |
| 4996 | } | ||
| 4997 | } | ||
| 4998 | } | ||
| 4999 | 3627793 | } | |
| 5000 | |||
| 5001 | /** | ||
| 5002 | Update equalities and keyuse references after semi-join materialization | ||
| 5003 | strategy is chosen. | ||
| 5004 | |||
| 5005 | @details | ||
| 5006 | For each multiple equality that contains a field that is selected | ||
| 5007 | from a subquery, and that subquery is executed using a semi-join | ||
| 5008 | materialization strategy, add the corresponding column in the materialized | ||
| 5009 | temporary table to the equality. | ||
| 5010 | For each injected semi-join equality that is not converted to | ||
| 5011 | multiple equality, replace the reference to the expression selected | ||
| 5012 | from the subquery with the corresponding column in the temporary table. | ||
| 5013 | |||
| 5014 | This is needed to properly reflect the equalities that involve injected | ||
| 5015 | semi-join equalities when materialization strategy is chosen. | ||
| 5016 | @see eliminate_item_equal() for how these equalities are used to generate | ||
| 5017 | correct equality predicates. | ||
| 5018 | |||
| 5019 | The MaterializeScan semi-join strategy requires some additional processing: | ||
| 5020 | All primary tables after the materialized temporary table must be inspected | ||
| 5021 | for keyuse objects that point to expressions from the subquery tables. | ||
| 5022 | These references must be replaced with references to corresponding columns | ||
| 5023 | in the materialized temporary table instead. Those primary tables using | ||
| 5024 | ref access will thus be made to depend on the materialized temporary table | ||
| 5025 | instead of the subquery tables. | ||
| 5026 | |||
| 5027 | Only the injected semi-join equalities need this treatment, other predicates | ||
| 5028 | will be handled correctly by the regular item substitution process. | ||
| 5029 | |||
| 5030 | @return False if success, true if error | ||
| 5031 | */ | ||
| 5032 | |||
| 5033 | 2721 | bool JOIN::update_equalities_for_sjm() { | |
| 5034 |
3/6✓ Branch 0 taken 2721 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2721 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2721 times.
✗ Branch 5 not taken.
|
2721 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 5035 |
1/2✓ Branch 0 taken 2721 times.
✗ Branch 1 not taken.
|
2721 | List_iterator<Semijoin_mat_exec> sj_it(sjm_exec_list); |
| 5036 | Semijoin_mat_exec *sjm_exec; | ||
| 5037 |
2/2✓ Branch 0 taken 934 times.
✓ Branch 1 taken 2721 times.
|
3655 | while ((sjm_exec = sj_it++)) { |
| 5038 | 934 | TABLE_LIST *const sj_nest = sjm_exec->sj_nest; | |
| 5039 | |||
| 5040 | Item *cond; | ||
| 5041 | /* | ||
| 5042 | Conditions involving SJ-inner tables are only to be found in the closest | ||
| 5043 | nest's condition, which may be an AJ nest, a LEFT JOIN nest, or the | ||
| 5044 | WHERE clause. | ||
| 5045 | */ | ||
| 5046 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 924 times.
|
934 | if (sj_nest->is_aj_nest()) |
| 5047 | 10 | cond = sj_nest->join_cond_optim(); | |
| 5048 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 910 times.
|
924 | else if (sj_nest->outer_join_nest()) |
| 5049 | 14 | cond = sj_nest->outer_join_nest()->join_cond_optim(); | |
| 5050 | else | ||
| 5051 | 910 | cond = where_cond; | |
| 5052 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 933 times.
|
934 | if (!cond) continue; |
| 5053 | |||
| 5054 | 933 | uchar *dummy = nullptr; | |
| 5055 |
1/2✓ Branch 0 taken 933 times.
✗ Branch 1 not taken.
|
933 | cond = cond->compile(&Item::equality_substitution_analyzer, &dummy, |
| 5056 | &Item::equality_substitution_transformer, | ||
| 5057 | (uchar *)sj_nest); | ||
| 5058 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 933 times.
|
933 | if (cond == nullptr) return true; |
| 5059 | |||
| 5060 |
1/2✓ Branch 0 taken 933 times.
✗ Branch 1 not taken.
|
933 | cond->update_used_tables(); |
| 5061 | |||
| 5062 | // Loop over all primary tables that follow the materialized table | ||
| 5063 |
2/2✓ Branch 0 taken 1137 times.
✓ Branch 1 taken 933 times.
|
2070 | for (uint j = sjm_exec->mat_table_index + 1; j < primary_tables; j++) { |
| 5064 | 1137 | JOIN_TAB *const tab = best_ref[j]; | |
| 5065 | 2247 | for (Key_use *keyuse = tab->position()->key; | |
| 5066 |
6/6✓ Branch 0 taken 2173 times.
✓ Branch 1 taken 74 times.
✓ Branch 2 taken 1114 times.
✓ Branch 3 taken 1059 times.
✓ Branch 4 taken 1110 times.
✓ Branch 5 taken 1137 times.
|
3361 | keyuse && keyuse->table_ref == tab->table_ref && |
| 5067 |
2/2✓ Branch 0 taken 1110 times.
✓ Branch 1 taken 4 times.
|
1114 | keyuse->key == tab->position()->key->key; |
| 5068 | keyuse++) { | ||
| 5069 | 1110 | uint fieldno = 0; | |
| 5070 |
6/10✓ Branch 0 taken 1110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1110 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1111 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1422 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1111 times.
✓ Branch 9 taken 311 times.
|
1422 | for (Item *old : sj_nest->nested_join->sj_inner_exprs) { |
| 5071 |
5/8✓ Branch 0 taken 1111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1111 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1111 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 799 times.
✓ Branch 7 taken 312 times.
|
1111 | if (old->real_item()->eq(keyuse->val->real_item(), false)) { |
| 5072 | /* | ||
| 5073 | Replace the expression selected from the subquery with the | ||
| 5074 | corresponding column of the materialized temporary table. | ||
| 5075 | */ | ||
| 5076 | 799 | keyuse->val = sj_nest->nested_join->sjm.mat_fields[fieldno]; | |
| 5077 |
1/2✓ Branch 0 taken 799 times.
✗ Branch 1 not taken.
|
799 | keyuse->used_tables = keyuse->val->used_tables(); |
| 5078 | 799 | break; | |
| 5079 | } | ||
| 5080 |
1/2✓ Branch 0 taken 312 times.
✗ Branch 1 not taken.
|
312 | fieldno++; |
| 5081 | } | ||
| 5082 | } | ||
| 5083 | } | ||
| 5084 | } | ||
| 5085 | |||
| 5086 | 2721 | return false; | |
| 5087 | } | ||
| 5088 | |||
| 5089 | /** | ||
| 5090 | Assign set of available (prefix) tables to all tables in query block. | ||
| 5091 | Also set added tables, ie the tables added in each JOIN_TAB compared to the | ||
| 5092 | previous JOIN_TAB. | ||
| 5093 | This function must be called for every query block after the table order | ||
| 5094 | has been determined. | ||
| 5095 | */ | ||
| 5096 | |||
| 5097 | 1815620 | void JOIN::set_prefix_tables() { | |
| 5098 |
3/6✓ Branch 0 taken 1815623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1815626 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1815637 times.
✗ Branch 5 not taken.
|
1815620 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 5099 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1815638 times.
|
1815634 | assert(!plan_is_const()); |
| 5100 | /* | ||
| 5101 | The const tables are available together with the first non-const table in | ||
| 5102 | the join order. | ||
| 5103 | */ | ||
| 5104 | 1815638 | table_map const initial_tables_map = | |
| 5105 |
2/2✓ Branch 0 taken 1815488 times.
✓ Branch 1 taken 150 times.
|
1815638 | const_table_map | (allow_outer_refs ? OUTER_REF_TABLE_BIT : 0); |
| 5106 | |||
| 5107 | 1815638 | table_map current_tables_map = initial_tables_map; | |
| 5108 | 1815638 | table_map prev_tables_map = (table_map)0; | |
| 5109 | 1815638 | table_map saved_tables_map = (table_map)0; | |
| 5110 | |||
| 5111 | 1815638 | JOIN_TAB *last_non_sjm_tab = nullptr; // Track the last non-sjm table | |
| 5112 | |||
| 5113 |
2/2✓ Branch 0 taken 6295701 times.
✓ Branch 1 taken 1815646 times.
|
8111347 | for (uint i = const_tables; i < tables; i++) { |
| 5114 | 6295701 | JOIN_TAB *const tab = best_ref[i]; | |
| 5115 |
2/2✓ Branch 0 taken 2467356 times.
✓ Branch 1 taken 3828360 times.
|
6295701 | if (!tab->table()) continue; |
| 5116 | /* | ||
| 5117 | Tables that are within SJ-Materialization nests cannot have their | ||
| 5118 | conditions referring to preceding non-const tables. | ||
| 5119 | - If we're looking at the first SJM table, reset current_tables_map | ||
| 5120 | to refer to only allowed tables | ||
| 5121 | @see Item_equal::get_subst_item() | ||
| 5122 | @see eliminate_item_equal() | ||
| 5123 | */ | ||
| 5124 |
2/2✓ Branch 0 taken 2374 times.
✓ Branch 1 taken 3825977 times.
|
3828360 | if (sj_is_materialize_strategy(tab->get_sj_strategy())) { |
| 5125 | 2374 | const table_map sjm_inner_tables = tab->emb_sj_nest->sj_inner_tables; | |
| 5126 |
2/2✓ Branch 0 taken 934 times.
✓ Branch 1 taken 1440 times.
|
2374 | if (!(sjm_inner_tables & current_tables_map)) { |
| 5127 | 934 | saved_tables_map = current_tables_map; | |
| 5128 | 934 | current_tables_map = initial_tables_map; | |
| 5129 | 934 | prev_tables_map = (table_map)0; | |
| 5130 | } | ||
| 5131 | |||
| 5132 | 2374 | current_tables_map |= tab->table_ref->map(); | |
| 5133 | 2374 | tab->set_prefix_tables(current_tables_map, prev_tables_map); | |
| 5134 | 2374 | prev_tables_map = current_tables_map; | |
| 5135 | |||
| 5136 |
2/2✓ Branch 0 taken 934 times.
✓ Branch 1 taken 1440 times.
|
2374 | if (!(sjm_inner_tables & ~current_tables_map)) { |
| 5137 | /* | ||
| 5138 | At the end of a semi-join materialization nest, | ||
| 5139 | add non-deterministic expressions to the last table of the nest: | ||
| 5140 | */ | ||
| 5141 | 934 | tab->add_prefix_tables(RAND_TABLE_BIT); | |
| 5142 | |||
| 5143 | // Restore the previous map: | ||
| 5144 | 934 | current_tables_map = saved_tables_map; | |
| 5145 | 934 | prev_tables_map = | |
| 5146 |
1/2✓ Branch 0 taken 934 times.
✗ Branch 1 not taken.
|
934 | last_non_sjm_tab ? last_non_sjm_tab->prefix_tables() : (table_map)0; |
| 5147 | } | ||
| 5148 | } else { | ||
| 5149 | 3825977 | last_non_sjm_tab = tab; | |
| 5150 | 3825977 | current_tables_map |= tab->table_ref->map(); | |
| 5151 | 3825979 | tab->set_prefix_tables(current_tables_map, prev_tables_map); | |
| 5152 | 3825979 | prev_tables_map = current_tables_map; | |
| 5153 | } | ||
| 5154 | } | ||
| 5155 | /* | ||
| 5156 | Non-deterministic expressions must be added to the last table's condition. | ||
| 5157 | It solves problem with queries like SELECT * FROM t1 WHERE rand() > 0.5 | ||
| 5158 | */ | ||
| 5159 |
2/2✓ Branch 0 taken 1815642 times.
✓ Branch 1 taken 4 times.
|
1815646 | if (last_non_sjm_tab != nullptr) |
| 5160 | 1815642 | last_non_sjm_tab->add_prefix_tables(RAND_TABLE_BIT); | |
| 5161 | 1815644 | } | |
| 5162 | |||
| 5163 | /** | ||
| 5164 | Calculate best possible join order and initialize the join structure. | ||
| 5165 | |||
| 5166 | @return true if success, false if error. | ||
| 5167 | |||
| 5168 | The JOIN object is populated with statistics about the query, | ||
| 5169 | and a plan with table order and access method selection is made. | ||
| 5170 | |||
| 5171 | The list of tables to be optimized is taken from query_block->leaf_tables. | ||
| 5172 | JOIN::where_cond is also used in the optimization. | ||
| 5173 | As a side-effect, JOIN::keyuse_array is populated with key_use information. | ||
| 5174 | |||
| 5175 | Here is an overview of the logic of this function: | ||
| 5176 | |||
| 5177 | - Initialize JOIN data structures and setup basic dependencies between tables. | ||
| 5178 | |||
| 5179 | - Update dependencies based on join information. | ||
| 5180 | |||
| 5181 | - Make key descriptions (update_ref_and_keys()). | ||
| 5182 | |||
| 5183 | - Pull out semi-join tables based on table dependencies. | ||
| 5184 | |||
| 5185 | - Extract tables with zero or one rows as const tables. | ||
| 5186 | |||
| 5187 | - Read contents of const tables, substitute columns from these tables with | ||
| 5188 | actual data. Also keep track of empty tables vs. one-row tables. | ||
| 5189 | |||
| 5190 | - After const table extraction based on row count, more tables may | ||
| 5191 | have become functionally dependent. Extract these as const tables. | ||
| 5192 | |||
| 5193 | - Add new sargable predicates based on retrieved const values. | ||
| 5194 | |||
| 5195 | - Calculate number of rows to be retrieved from each table. | ||
| 5196 | |||
| 5197 | - Calculate cost of potential semi-join materializations. | ||
| 5198 | |||
| 5199 | - Calculate best possible join order based on available statistics. | ||
| 5200 | |||
| 5201 | - Fill in remaining information for the generated join order. | ||
| 5202 | */ | ||
| 5203 | |||
| 5204 | 1912109 | bool JOIN::make_join_plan() { | |
| 5205 |
1/2✓ Branch 0 taken 1912125 times.
✗ Branch 1 not taken.
|
1912109 | DBUG_TRACE; |
| 5206 | |||
| 5207 | 1912125 | SARGABLE_PARAM *sargables = nullptr; | |
| 5208 | |||
| 5209 | 1912125 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 5210 | |||
| 5211 |
3/4✓ Branch 0 taken 1912120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1912118 times.
|
1912125 | if (init_planner_arrays()) // Create and initialize the arrays |
| 5212 | 2 | return true; | |
| 5213 | |||
| 5214 | // Outer join dependencies were initialized above, now complete the analysis. | ||
| 5215 |
6/6✓ Branch 0 taken 1761434 times.
✓ Branch 1 taken 150684 times.
✓ Branch 2 taken 492 times.
✓ Branch 3 taken 1760943 times.
✓ Branch 4 taken 151177 times.
✓ Branch 5 taken 1760942 times.
|
1912118 | if (query_block->outer_join || query_block->is_recursive()) { |
| 5216 |
3/4✓ Branch 0 taken 151175 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 151171 times.
|
151177 | if (propagate_dependencies()) { |
| 5217 | /* | ||
| 5218 | Catch illegal join order. | ||
| 5219 | SQL2011 forbids: | ||
| 5220 | WITH RECURSIVE rec AS ( | ||
| 5221 | ... UNION ALL SELECT ... FROM tbl LEFT JOIN rec ON...)c... | ||
| 5222 | MySQL also forbids the same query with STRAIGHT_JOIN instead of LEFT | ||
| 5223 | JOIN, because the algorithm of with-recursive imposes that "rec" be | ||
| 5224 | first in plan, i.e. "tbl" depends on "rec", but STRAIGHT_JOIN imposes | ||
| 5225 | the opposite dependency. | ||
| 5226 | */ | ||
| 5227 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | assert(query_block->is_recursive()); |
| 5228 | 4 | my_error(ER_CTE_RECURSIVE_FORBIDDEN_JOIN_ORDER, MYF(0), | |
| 5229 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | query_block->recursive_reference->alias); |
| 5230 | 4 | return true; | |
| 5231 | } | ||
| 5232 | 151171 | init_key_dependencies(); | |
| 5233 | } | ||
| 5234 | |||
| 5235 |
2/2✓ Branch 0 taken 2702 times.
✓ Branch 1 taken 1909417 times.
|
1912115 | if (unlikely(trace->is_started())) |
| 5236 |
1/2✓ Branch 0 taken 2702 times.
✗ Branch 1 not taken.
|
2702 | trace_table_dependencies(trace, join_tab, primary_tables); |
| 5237 | |||
| 5238 | // Build the key access information, which is the basis for ref access. | ||
| 5239 |
4/4✓ Branch 0 taken 606911 times.
✓ Branch 1 taken 1305208 times.
✓ Branch 2 taken 4092 times.
✓ Branch 3 taken 602819 times.
|
1912119 | if (where_cond || query_block->outer_join) { |
| 5240 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1309292 times.
|
1309292 | if (update_ref_and_keys(thd, &keyuse_array, join_tab, tables, where_cond, |
| 5241 |
1/2✓ Branch 0 taken 1309292 times.
✗ Branch 1 not taken.
|
1309300 | ~query_block->outer_join, query_block, &sargables)) |
| 5242 | ✗ | return true; | |
| 5243 | } | ||
| 5244 | |||
| 5245 | /* | ||
| 5246 | Pull out semi-join tables based on dependencies. Dependencies are valid | ||
| 5247 | throughout the lifetime of a query, so this operation can be performed | ||
| 5248 | on the first optimization only. | ||
| 5249 | */ | ||
| 5250 |
6/8✓ Branch 0 taken 1726616 times.
✓ Branch 1 taken 185495 times.
✓ Branch 2 taken 1726617 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4435 times.
✓ Branch 5 taken 1722182 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1912112 times.
|
1916546 | if (!query_block->sj_pullout_done && !query_block->sj_nests.empty() && |
| 5251 |
2/4✓ Branch 0 taken 4435 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4435 times.
|
4435 | pull_out_semijoin_tables(this)) |
| 5252 | ✗ | return true; | |
| 5253 | |||
| 5254 | 1912112 | query_block->sj_pullout_done = true; | |
| 5255 | 1912112 | const uint sj_nests = query_block->sj_nests.size(); // Changed by pull-out | |
| 5256 | |||
| 5257 |
2/2✓ Branch 0 taken 1908158 times.
✓ Branch 1 taken 3953 times.
|
1912107 | if (!(query_block->active_options() & OPTION_NO_CONST_TABLES)) { |
| 5258 | // Detect tables that are const (0 or 1 row) and read their contents. | ||
| 5259 |
2/4✓ Branch 0 taken 1908167 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1908167 times.
|
1908158 | if (extract_const_tables()) return true; |
| 5260 | |||
| 5261 | // Detect tables that are functionally dependent on const values. | ||
| 5262 |
3/4✓ Branch 0 taken 1908167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87 times.
✓ Branch 3 taken 1908080 times.
|
1908167 | if (extract_func_dependent_tables()) return true; |
| 5263 | } | ||
| 5264 | // Possibly able to create more sargable predicates from const rows. | ||
| 5265 |
5/6✓ Branch 0 taken 98405 times.
✓ Branch 1 taken 1813628 times.
✓ Branch 2 taken 90395 times.
✓ Branch 3 taken 8010 times.
✓ Branch 4 taken 90396 times.
✗ Branch 5 not taken.
|
1912033 | if (const_tables && sargables) update_sargable_from_const(sargables); |
| 5266 | |||
| 5267 | // Make a first estimate of the fanout for each table in the query block. | ||
| 5268 |
2/4✓ Branch 0 taken 1912030 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1912030 times.
|
1912034 | if (estimate_rowcount()) return true; |
| 5269 | |||
| 5270 | /* | ||
| 5271 | Apply join order hints, with the exception of | ||
| 5272 | JOIN_FIXED_ORDER and STRAIGHT_JOIN. | ||
| 5273 | */ | ||
| 5274 |
4/4✓ Branch 0 taken 11170 times.
✓ Branch 1 taken 1900860 times.
✓ Branch 2 taken 11165 times.
✓ Branch 3 taken 1900865 times.
|
1923200 | if (query_block->opt_hints_qb && |
| 5275 |
2/2✓ Branch 0 taken 11165 times.
✓ Branch 1 taken 5 times.
|
11170 | !(query_block->active_options() & SELECT_STRAIGHT_JOIN)) |
| 5276 |
1/2✓ Branch 0 taken 11165 times.
✗ Branch 1 not taken.
|
11165 | query_block->opt_hints_qb->apply_join_order_hints(this); |
| 5277 | |||
| 5278 |
2/2✓ Branch 0 taken 2721 times.
✓ Branch 1 taken 1909309 times.
|
1912030 | if (sj_nests) { |
| 5279 |
1/2✓ Branch 0 taken 2721 times.
✗ Branch 1 not taken.
|
2721 | set_semijoin_embedding(); |
| 5280 |
1/2✓ Branch 0 taken 2721 times.
✗ Branch 1 not taken.
|
2721 | query_block->update_semijoin_strategies(thd); |
| 5281 | } | ||
| 5282 | |||
| 5283 |
3/4✓ Branch 0 taken 1815657 times.
✓ Branch 1 taken 96354 times.
✓ Branch 2 taken 1815673 times.
✗ Branch 3 not taken.
|
1912030 | if (!plan_is_const()) optimize_keyuse(); |
| 5284 | |||
| 5285 | 1912027 | allow_outer_refs = true; | |
| 5286 | |||
| 5287 |
5/8✓ Branch 0 taken 2721 times.
✓ Branch 1 taken 1909306 times.
✓ Branch 2 taken 2721 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2721 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1912027 times.
|
1912027 | if (sj_nests && optimize_semijoin_nests_for_materialization(this)) |
| 5288 | ✗ | return true; | |
| 5289 | |||
| 5290 | // Choose the table order based on analysis done so far. | ||
| 5291 |
4/6✓ Branch 0 taken 1912029 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1912032 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 1912022 times.
|
1912027 | if (Optimize_table_order(thd, this, nullptr).choose_table_order()) |
| 5292 | 10 | return true; | |
| 5293 | |||
| 5294 |
3/4✓ Branch 0 taken 1912021 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1912019 times.
|
1912022 | DBUG_EXECUTE_IF("bug13820776_1", thd->killed = THD::KILL_QUERY;); |
| 5295 |
7/8✓ Branch 0 taken 1912013 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1912018 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1912017 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 1912017 times.
|
1912021 | if (thd->killed || thd->is_error()) return true; |
| 5296 | |||
| 5297 | // If this is a subquery, decide between In-to-exists and materialization | ||
| 5298 |
7/8✓ Branch 0 taken 81721 times.
✓ Branch 1 taken 1830294 times.
✓ Branch 2 taken 81723 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 81716 times.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 1912010 times.
|
1912017 | if (query_expression()->item && decide_subquery_strategy()) return true; |
| 5299 | |||
| 5300 |
1/2✓ Branch 0 taken 1911996 times.
✗ Branch 1 not taken.
|
1912010 | refine_best_rowcount(); |
| 5301 | |||
| 5302 | 3824121 | if (!(thd->variables.option_bits & OPTION_BIG_SELECTS) && | |
| 5303 |
6/6✓ Branch 0 taken 129 times.
✓ Branch 1 taken 1911867 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 116 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 1911983 times.
|
1912009 | best_read > (double)thd->variables.max_join_size && |
| 5304 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | !thd->lex->is_explain()) { /* purecov: inspected */ |
| 5305 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | my_error(ER_TOO_BIG_SELECT, MYF(0)); |
| 5306 | 13 | error = -1; | |
| 5307 | 13 | return true; | |
| 5308 | } | ||
| 5309 | |||
| 5310 | 1911983 | positions = nullptr; // But keep best_positions for get_best_combination | |
| 5311 | |||
| 5312 | // Generate an execution plan from the found optimal join order. | ||
| 5313 |
2/4✓ Branch 0 taken 1911992 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1911992 times.
|
1911983 | if (get_best_combination()) return true; |
| 5314 | |||
| 5315 | // Cleanup after update_ref_and_keys has added keys for derived tables. | ||
| 5316 |
3/4✓ Branch 0 taken 145210 times.
✓ Branch 1 taken 1766782 times.
✓ Branch 2 taken 145210 times.
✗ Branch 3 not taken.
|
1911992 | if (query_block->materialized_derived_table_count) finalize_derived_keys(); |
| 5317 | |||
| 5318 | // No need for this struct after new JOIN_TAB array is set up. | ||
| 5319 | 1911992 | best_positions = nullptr; | |
| 5320 | |||
| 5321 | // Some called function may still set error status unnoticed | ||
| 5322 |
2/4✓ Branch 0 taken 1911989 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1911989 times.
|
1911992 | if (thd->is_error()) return true; |
| 5323 | |||
| 5324 | // There is at least one empty const table | ||
| 5325 |
2/2✓ Branch 0 taken 8533 times.
✓ Branch 1 taken 1903456 times.
|
1911989 | if (const_table_map != found_const_table_map) |
| 5326 | 8533 | zero_result_cause = "no matching row in const table"; | |
| 5327 | |||
| 5328 | 1911989 | return false; | |
| 5329 | 1912115 | } | |
| 5330 | |||
| 5331 | /** | ||
| 5332 | Initialize scratch arrays for the join order optimization | ||
| 5333 | |||
| 5334 | @returns false if success, true if error | ||
| 5335 | |||
| 5336 | @note If something fails during initialization, JOIN::cleanup() | ||
| 5337 | will free anything that has been partially allocated and set up. | ||
| 5338 | Arrays are created in the execution mem_root, so they will be | ||
| 5339 | deleted automatically when the mem_root is re-initialized. | ||
| 5340 | */ | ||
| 5341 | |||
| 5342 | 1912108 | bool JOIN::init_planner_arrays() { | |
| 5343 | // Up to one extra slot per semi-join nest is needed (if materialized) | ||
| 5344 | 1912108 | const uint sj_nests = query_block->sj_nests.size(); | |
| 5345 | 1912121 | const uint table_count = query_block->leaf_table_count; | |
| 5346 | |||
| 5347 |
3/4✓ Branch 0 taken 1912120 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1912124 times.
✗ Branch 3 not taken.
|
1912121 | assert(primary_tables == 0 && tables == 0); |
| 5348 | |||
| 5349 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1912120 times.
|
1912124 | if (!(join_tab = alloc_jtab_array(thd, table_count))) return true; |
| 5350 | |||
| 5351 | /* | ||
| 5352 | We add 2 cells: | ||
| 5353 | - because planning stage uses 0-termination so needs +1 | ||
| 5354 | - because after get_best_combination, we don't use 0-termination but | ||
| 5355 | need +2, to host at most 2 tmp sort/group/distinct tables. | ||
| 5356 | */ | ||
| 5357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1912122 times.
|
1912122 | if (!(best_ref = (JOIN_TAB **)thd->alloc( |
| 5358 | sizeof(JOIN_TAB *) * | ||
| 5359 | 1912120 | (table_count + sj_nests + 2 + m_windows.elements)))) | |
| 5360 | ✗ | return true; | |
| 5361 | |||
| 5362 | // sort/group tmp tables have no map | ||
| 5363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1912125 times.
|
1912125 | if (!(map2table = (JOIN_TAB **)thd->alloc(sizeof(JOIN_TAB *) * |
| 5364 | 1912122 | (table_count + sj_nests)))) | |
| 5365 | ✗ | return true; | |
| 5366 | |||
| 5367 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1912124 times.
|
1912125 | if (!(positions = new (thd->mem_root) POSITION[table_count])) return true; |
| 5368 | |||
| 5369 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1912124 times.
|
1912124 | if (!(best_positions = new (thd->mem_root) POSITION[table_count + sj_nests])) |
| 5370 | ✗ | return true; | |
| 5371 | |||
| 5372 | /* | ||
| 5373 | Initialize data structures for tables to be joined. | ||
| 5374 | Initialize dependencies between tables. | ||
| 5375 | */ | ||
| 5376 | 1912124 | JOIN_TAB **best_ref_p = best_ref; | |
| 5377 | 1912124 | TABLE_LIST *tl = query_block->leaf_tables; | |
| 5378 | |||
| 5379 |
2/2✓ Branch 0 taken 3928595 times.
✓ Branch 1 taken 1912115 times.
|
5840710 | for (JOIN_TAB *tab = join_tab; tl; tab++, tl = tl->next_leaf, best_ref_p++) { |
| 5380 | 3928595 | *best_ref_p = tab; | |
| 5381 | 3928595 | TABLE *const table = tl->table; | |
| 5382 | 3928595 | tab->table_ref = tl; | |
| 5383 | 3928595 | tab->set_table(table); | |
| 5384 | 3928588 | const int err = tl->fetch_number_of_rows(); | |
| 5385 | |||
| 5386 | // Initialize the cost model for the table | ||
| 5387 | 3928603 | table->init_cost_model(cost_model()); | |
| 5388 | |||
| 5389 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 3928602 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3928594 | DBUG_EXECUTE_IF("bug11747970_raise_error", { |
| 5390 | if (!err) { | ||
| 5391 | my_error(ER_UNKNOWN_ERROR, MYF(0)); | ||
| 5392 | return true; | ||
| 5393 | } | ||
| 5394 | }); | ||
| 5395 | |||
| 5396 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3928600 times.
|
3928602 | if (err) { |
| 5397 | 2 | table->file->print_error(err, MYF(0)); | |
| 5398 | 2 | return true; | |
| 5399 | } | ||
| 5400 | 3928600 | all_table_map |= tl->map(); | |
| 5401 | 3928601 | tab->set_join(this); | |
| 5402 | |||
| 5403 |
6/6✓ Branch 0 taken 3868357 times.
✓ Branch 1 taken 60241 times.
✓ Branch 2 taken 2383 times.
✓ Branch 3 taken 3865970 times.
✓ Branch 4 taken 62624 times.
✓ Branch 5 taken 3865970 times.
|
3928596 | if (tl->is_updated() || tl->is_deleted()) { |
| 5404 | // As we update or delete rows, we can't read the index | ||
| 5405 | 62624 | table->no_keyread = true; | |
| 5406 | } | ||
| 5407 | |||
| 5408 | 3928594 | tab->dependent = tl->dep_tables; // Initialize table dependencies | |
| 5409 |
2/2✓ Branch 0 taken 713 times.
✓ Branch 1 taken 3927874 times.
|
3928594 | if (query_block->is_recursive()) { |
| 5410 |
2/2✓ Branch 0 taken 216 times.
✓ Branch 1 taken 497 times.
|
713 | if (query_block->recursive_reference != tl) |
| 5411 | // Recursive reference must go first | ||
| 5412 | 216 | tab->dependent |= query_block->recursive_reference->map(); | |
| 5413 | else { | ||
| 5414 | // Recursive reference mustn't use any index | ||
| 5415 | 497 | table->covering_keys.clear_all(); | |
| 5416 | 497 | table->keys_in_use_for_group_by.clear_all(); | |
| 5417 | 497 | table->keys_in_use_for_order_by.clear_all(); | |
| 5418 | } | ||
| 5419 | } | ||
| 5420 |
2/2✓ Branch 0 taken 251471 times.
✓ Branch 1 taken 3677117 times.
|
3928588 | if (tl->schema_table) table->file->stats.records = 2; |
| 5421 | 3928588 | table->quick_condition_rows = table->file->stats.records; | |
| 5422 | |||
| 5423 | 3928588 | tab->init_join_cond_ref(tl); | |
| 5424 | |||
| 5425 |
2/2✓ Branch 0 taken 3759 times.
✓ Branch 1 taken 3924821 times.
|
3928583 | if (tl->outer_join_nest()) { |
| 5426 | // tab belongs to a nested join, maybe to several embedding joins | ||
| 5427 | 3759 | tab->embedding_map = 0; | |
| 5428 |
2/2✓ Branch 0 taken 4097 times.
✓ Branch 1 taken 3759 times.
|
7856 | for (TABLE_LIST *embedding = tl->embedding; embedding; |
| 5429 | 4097 | embedding = embedding->embedding) { | |
| 5430 | 4097 | NESTED_JOIN *const nested_join = embedding->nested_join; | |
| 5431 | 4097 | tab->embedding_map |= nested_join->nj_map; | |
| 5432 | 4097 | tab->dependent |= embedding->dep_tables; | |
| 5433 | } | ||
| 5434 |
2/2✓ Branch 0 taken 401518 times.
✓ Branch 1 taken 3523307 times.
|
3924821 | } else if (tab->join_cond()) { |
| 5435 | // tab is the only inner table of an outer join | ||
| 5436 | 401518 | tab->embedding_map = 0; | |
| 5437 |
2/2✓ Branch 0 taken 3780 times.
✓ Branch 1 taken 401518 times.
|
405298 | for (TABLE_LIST *embedding = tl->embedding; embedding; |
| 5438 | 3780 | embedding = embedding->embedding) | |
| 5439 | 3780 | tab->embedding_map |= embedding->nested_join->nj_map; | |
| 5440 | } | ||
| 5441 | |||
| 5442 |
6/6✓ Branch 0 taken 143724 times.
✓ Branch 1 taken 3784862 times.
✓ Branch 2 taken 564 times.
✓ Branch 3 taken 143160 times.
✓ Branch 4 taken 564 times.
✓ Branch 5 taken 3928022 times.
|
3928584 | if (tl->is_derived() && tl->derived_query_expression()->m_lateral_deps) |
| 5443 | 564 | has_lateral = true; | |
| 5444 | |||
| 5445 | 3928586 | tables++; // Count number of initialized tables | |
| 5446 | } | ||
| 5447 | |||
| 5448 | 1912115 | primary_tables = tables; | |
| 5449 | 1912115 | *best_ref_p = nullptr; // Last element of array must be NULL | |
| 5450 | |||
| 5451 | 1912115 | return false; | |
| 5452 | } | ||
| 5453 | |||
| 5454 | /** | ||
| 5455 | Propagate dependencies between tables due to outer join relations. | ||
| 5456 | |||
| 5457 | @returns false if success, true if error | ||
| 5458 | |||
| 5459 | Build transitive closure for relation 'to be dependent on'. | ||
| 5460 | This will speed up the plan search for many cases with outer joins, | ||
| 5461 | as well as allow us to catch illegal cross references. | ||
| 5462 | Warshall's algorithm is used to build the transitive closure. | ||
| 5463 | As we may restart the outer loop up to 'table_count' times, the | ||
| 5464 | complexity of the algorithm is O((number of tables)^3). | ||
| 5465 | However, most of the iterations will be shortcircuited when | ||
| 5466 | there are no dependencies to propagate. | ||
| 5467 | */ | ||
| 5468 | |||
| 5469 | 151286 | bool JOIN::propagate_dependencies() { | |
| 5470 |
2/2✓ Branch 0 taken 970017 times.
✓ Branch 1 taken 151291 times.
|
1121308 | for (uint i = 0; i < tables; i++) { |
| 5471 |
2/2✓ Branch 0 taken 564050 times.
✓ Branch 1 taken 405967 times.
|
970017 | if (!join_tab[i].dependent) continue; |
| 5472 | |||
| 5473 | // Add my dependencies to other tables depending on me | ||
| 5474 | uint j; | ||
| 5475 | JOIN_TAB *tab; | ||
| 5476 |
2/2✓ Branch 0 taken 2603079 times.
✓ Branch 1 taken 405944 times.
|
3009023 | for (j = 0, tab = join_tab; j < tables; j++, tab++) { |
| 5477 |
2/2✓ Branch 0 taken 258195 times.
✓ Branch 1 taken 2344889 times.
|
2603079 | if (tab->dependent & join_tab[i].table_ref->map()) { |
| 5478 | 258195 | const table_map was_dependent = tab->dependent; | |
| 5479 | 258195 | tab->dependent |= join_tab[i].dependent; | |
| 5480 | /* | ||
| 5481 | If we change dependencies for a table we already have | ||
| 5482 | processed: Redo dependency propagation from this table. | ||
| 5483 | */ | ||
| 5484 |
4/4✓ Branch 0 taken 271 times.
✓ Branch 1 taken 257924 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 243 times.
|
258195 | if (i > j && tab->dependent != was_dependent) { |
| 5485 | 28 | i = j - 1; | |
| 5486 | 28 | break; | |
| 5487 | } | ||
| 5488 | } | ||
| 5489 | } | ||
| 5490 | } | ||
| 5491 | |||
| 5492 | 151291 | JOIN_TAB *const tab_end = join_tab + tables; | |
| 5493 |
2/2✓ Branch 0 taken 969910 times.
✓ Branch 1 taken 151265 times.
|
1121175 | for (JOIN_TAB *tab = join_tab; tab < tab_end; tab++) { |
| 5494 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 969884 times.
|
969910 | if ((tab->dependent & tab->table_ref->map())) return true; |
| 5495 | } | ||
| 5496 | |||
| 5497 | 151265 | return false; | |
| 5498 | } | ||
| 5499 | |||
| 5500 | /** | ||
| 5501 | Extract const tables based on row counts. | ||
| 5502 | |||
| 5503 | @returns false if success, true if error | ||
| 5504 | |||
| 5505 | This extraction must be done for each execution. | ||
| 5506 | Tables containing exactly zero or one rows are marked as const, but | ||
| 5507 | notice the additional constraints checked below. | ||
| 5508 | Tables that are extracted have their rows read before actual execution | ||
| 5509 | starts and are placed in the beginning of the join_tab array. | ||
| 5510 | Thus, they do not take part in join order optimization process, | ||
| 5511 | which can significantly reduce the optimization time. | ||
| 5512 | The data read from these tables can also be regarded as "constant" | ||
| 5513 | throughout query execution, hence the column values can be used for | ||
| 5514 | additional constant propagation and extraction of const tables based | ||
| 5515 | on eq-ref properties. | ||
| 5516 | |||
| 5517 | The tables are given the type JT_SYSTEM. | ||
| 5518 | */ | ||
| 5519 | |||
| 5520 | 1908147 | bool JOIN::extract_const_tables() { | |
| 5521 | enum enum_const_table_extraction { | ||
| 5522 | extract_no_table = 0, | ||
| 5523 | extract_empty_table = 1, | ||
| 5524 | extract_const_table = 2 | ||
| 5525 | }; | ||
| 5526 | |||
| 5527 | 1908147 | JOIN_TAB *const tab_end = join_tab + tables; | |
| 5528 |
2/2✓ Branch 0 taken 3924471 times.
✓ Branch 1 taken 1908170 times.
|
5832641 | for (JOIN_TAB *tab = join_tab; tab < tab_end; tab++) { |
| 5529 | 3924471 | TABLE *const table = tab->table(); | |
| 5530 | 3924495 | TABLE_LIST *const tl = tab->table_ref; | |
| 5531 | 3924495 | enum enum_const_table_extraction extract_method = extract_const_table; | |
| 5532 | |||
| 5533 | 3924495 | const bool all_partitions_pruned_away = table->all_partitions_pruned_away; | |
| 5534 | |||
| 5535 |
2/2✓ Branch 0 taken 3759 times.
✓ Branch 1 taken 3920746 times.
|
3924495 | if (tl->outer_join_nest()) { |
| 5536 | /* | ||
| 5537 | Table belongs to a nested join, no candidate for const table extraction. | ||
| 5538 | */ | ||
| 5539 | 3759 | extract_method = extract_no_table; | |
| 5540 |
5/6✓ Branch 0 taken 10161 times.
✓ Branch 1 taken 3910585 times.
✓ Branch 2 taken 10161 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10161 times.
✓ Branch 5 taken 3910585 times.
|
3920746 | } else if (tl->embedding && tl->embedding->is_sj_or_aj_nest()) { |
| 5541 | /* | ||
| 5542 | Table belongs to a semi-join. | ||
| 5543 | We do not currently pull out const tables from semi-join nests. | ||
| 5544 | */ | ||
| 5545 | 10161 | extract_method = extract_no_table; | |
| 5546 |
2/2✓ Branch 0 taken 397694 times.
✓ Branch 1 taken 3512877 times.
|
3910585 | } else if (tab->join_cond()) { |
| 5547 | // tab is the only inner table of an outer join, extract empty tables | ||
| 5548 | 397694 | extract_method = extract_empty_table; | |
| 5549 | } | ||
| 5550 |
4/4✓ Branch 0 taken 13920 times.
✓ Branch 1 taken 397693 times.
✓ Branch 2 taken 3512877 times.
✓ Branch 3 taken 1 times.
|
3924491 | switch (extract_method) { |
| 5551 | 13920 | case extract_no_table: | |
| 5552 | 13920 | break; | |
| 5553 | |||
| 5554 | 397693 | case extract_empty_table: | |
| 5555 | // Extract tables with zero rows, but only if statistics are exact | ||
| 5556 |
5/6✓ Branch 0 taken 397628 times.
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 397628 times.
✓ Branch 4 taken 65 times.
✓ Branch 5 taken 397629 times.
|
397759 | if ((table->file->stats.records == 0 || all_partitions_pruned_away) && |
| 5557 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 1 times.
|
65 | (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT)) |
| 5558 | 65 | mark_const_table(tab, nullptr); | |
| 5559 | 397694 | break; | |
| 5560 | |||
| 5561 | 3512877 | case extract_const_table: | |
| 5562 | /* | ||
| 5563 | Extract tables with zero or one rows, but do not extract tables that | ||
| 5564 | 1. are dependent upon other tables, or | ||
| 5565 | 2. have no exact statistics, or | ||
| 5566 | 3. are full-text searched | ||
| 5567 | */ | ||
| 5568 |
3/4✓ Branch 0 taken 2871832 times.
✓ Branch 1 taken 641041 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2871832 times.
|
3512873 | if ((table->s->system || table->file->stats.records <= 1 || |
| 5569 | 641045 | all_partitions_pruned_away) && | |
| 5570 |
2/2✓ Branch 0 taken 640609 times.
✓ Branch 1 taken 436 times.
|
641045 | !tab->dependent && // 1 |
| 5571 |
6/6✓ Branch 0 taken 3512873 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 14501 times.
✓ Branch 3 taken 626105 times.
✓ Branch 4 taken 14464 times.
✓ Branch 5 taken 3498412 times.
|
7040257 | (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) && // 2 |
| 5572 |
2/2✓ Branch 0 taken 14464 times.
✓ Branch 1 taken 39 times.
|
14501 | !tl->is_fulltext_searched()) // 3 |
| 5573 | 14464 | mark_const_table(tab, nullptr); | |
| 5574 | 3512879 | break; | |
| 5575 | } | ||
| 5576 | } | ||
| 5577 | |||
| 5578 | // Read const tables (tables matching no more than 1 rows) | ||
| 5579 |
2/2✓ Branch 0 taken 1893980 times.
✓ Branch 1 taken 14190 times.
|
1908170 | if (!const_tables) return false; |
| 5580 | |||
| 5581 | 28721 | for (POSITION *p_pos = positions, *p_end = p_pos + const_tables; | |
| 5582 |
2/2✓ Branch 0 taken 14530 times.
✓ Branch 1 taken 14191 times.
|
28721 | p_pos < p_end; p_pos++) { |
| 5583 | 14530 | JOIN_TAB *const tab = p_pos->table; | |
| 5584 | 14530 | const int status = join_read_const_table(tab, p_pos); | |
| 5585 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14531 times.
|
14531 | if (status > 0) |
| 5586 | ✗ | return true; | |
| 5587 |
2/2✓ Branch 0 taken 9850 times.
✓ Branch 1 taken 4681 times.
|
14531 | else if (status == 0) { |
| 5588 | 9850 | found_const_table_map |= tab->table_ref->map(); | |
| 5589 | 9850 | tab->table_ref->optimized_away = true; | |
| 5590 | } | ||
| 5591 | } | ||
| 5592 | |||
| 5593 | 14191 | return false; | |
| 5594 | } | ||
| 5595 | |||
| 5596 | /** | ||
| 5597 | Extract const tables based on functional dependencies. | ||
| 5598 | |||
| 5599 | @returns false if success, true if error | ||
| 5600 | |||
| 5601 | This extraction must be done for each execution. | ||
| 5602 | |||
| 5603 | Mark as const the tables that | ||
| 5604 | - are functionally dependent on constant values, or | ||
| 5605 | - are inner tables of an outer join and contain exactly zero or one rows | ||
| 5606 | |||
| 5607 | Tables that are extracted have their rows read before actual execution | ||
| 5608 | starts and are placed in the beginning of the join_tab array, just as | ||
| 5609 | described for JOIN::extract_const_tables(). | ||
| 5610 | |||
| 5611 | The tables are given the type JT_CONST. | ||
| 5612 | */ | ||
| 5613 | |||
| 5614 | 1908275 | bool JOIN::extract_func_dependent_tables() { | |
| 5615 | // loop until no more const tables are found | ||
| 5616 | bool ref_changed; | ||
| 5617 | // Tables referenced by others; if they're const the others may be too. | ||
| 5618 | table_map found_ref; | ||
| 5619 | do { | ||
| 5620 | 1908275 | more_const_tables_found: | |
| 5621 | 1908275 | ref_changed = false; | |
| 5622 | 1908275 | found_ref = 0; | |
| 5623 | |||
| 5624 | // Loop over all tables that are not already determined to be const | ||
| 5625 |
2/2✓ Branch 0 taken 3910232 times.
✓ Branch 1 taken 1908152 times.
|
5818384 | for (JOIN_TAB **pos = best_ref + const_tables; *pos; pos++) { |
| 5626 | 3910232 | JOIN_TAB *const tab = *pos; | |
| 5627 | 3910232 | TABLE *const table = tab->table(); | |
| 5628 | 3910249 | TABLE_LIST *const tl = tab->table_ref; | |
| 5629 | /* | ||
| 5630 | If equi-join condition by a key is null rejecting and after a | ||
| 5631 | substitution of a const table the key value happens to be null | ||
| 5632 | then we can state that there are no matches for this equi-join. | ||
| 5633 | */ | ||
| 5634 | 3910249 | Key_use *keyuse = tab->keyuse(); | |
| 5635 |
8/8✓ Branch 0 taken 2590970 times.
✓ Branch 1 taken 1319286 times.
✓ Branch 2 taken 397148 times.
✓ Branch 3 taken 2193822 times.
✓ Branch 4 taken 396977 times.
✓ Branch 5 taken 171 times.
✓ Branch 6 taken 396977 times.
✓ Branch 7 taken 3513279 times.
|
3910256 | if (keyuse && tab->join_cond() && !tab->embedding_map) { |
| 5636 | /* | ||
| 5637 | When performing an outer join operation if there are no matching rows | ||
| 5638 | for the single row of the outer table all the inner tables are to be | ||
| 5639 | null complemented and thus considered as constant tables. | ||
| 5640 | Here we apply this consideration to the case of outer join operations | ||
| 5641 | with a single inner table only because the case with nested tables | ||
| 5642 | would require a more thorough analysis. | ||
| 5643 | TODO. Apply single row substitution to null complemented inner tables | ||
| 5644 | for nested outer join operations. | ||
| 5645 | */ | ||
| 5646 |
2/2✓ Branch 0 taken 513824 times.
✓ Branch 1 taken 396931 times.
|
910755 | while (keyuse->table_ref == tl) { |
| 5647 | 513824 | if (!(keyuse->val->used_tables() & ~const_table_map) && | |
| 5648 |
8/8✓ Branch 0 taken 113745 times.
✓ Branch 1 taken 400090 times.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 113675 times.
✓ Branch 4 taken 49 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 43 times.
✓ Branch 7 taken 513778 times.
|
513884 | keyuse->val->is_null() && keyuse->null_rejecting && |
| 5649 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 43 times.
|
49 | (tl->embedding == nullptr || |
| 5650 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | !tl->embedding->is_sj_or_aj_nest())) { |
| 5651 | 43 | table->set_null_row(); | |
| 5652 | 43 | table->const_table = true; | |
| 5653 | 43 | found_const_table_map |= tl->map(); | |
| 5654 | 43 | mark_const_table(tab, keyuse); | |
| 5655 | 48 | goto more_const_tables_found; | |
| 5656 | } | ||
| 5657 | 513778 | keyuse++; | |
| 5658 | } | ||
| 5659 | } | ||
| 5660 | |||
| 5661 |
2/2✓ Branch 0 taken 407702 times.
✓ Branch 1 taken 3502508 times.
|
3910210 | if (tab->dependent) // If dependent on some table |
| 5662 | { | ||
| 5663 | // All dependent tables must be const | ||
| 5664 |
2/2✓ Branch 0 taken 407363 times.
✓ Branch 1 taken 339 times.
|
407702 | if (tab->dependent & ~const_table_map) { |
| 5665 | 407363 | found_ref |= tab->dependent; | |
| 5666 | 407363 | continue; | |
| 5667 | } | ||
| 5668 | /* | ||
| 5669 | Mark a dependent table as constant if | ||
| 5670 | 1. it has exactly zero or one rows (it is a system table), and | ||
| 5671 | 2. it is not within a nested outer join, and | ||
| 5672 | 3. it does not have an expensive outer join condition. | ||
| 5673 | This is because we have to determine whether an outer-joined table | ||
| 5674 | has a real row or a null-extended row in the optimizer phase. | ||
| 5675 | We have no possibility to evaluate its join condition at | ||
| 5676 | execution time, when it is marked as a system table. | ||
| 5677 | */ | ||
| 5678 | 809 | if (table->file->stats.records <= 1L && // 1 | |
| 5679 |
4/4✓ Branch 0 taken 73 times.
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 44 times.
|
202 | (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) && // 1 |
| 5680 |
6/6✓ Branch 0 taken 129 times.
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 312 times.
|
554 | !tl->outer_join_nest() && // 2 |
| 5681 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2 times.
|
40 | !(tab->join_cond() && tab->join_cond()->is_expensive())) // 3 |
| 5682 | { // system table | ||
| 5683 | 29 | mark_const_table(tab, nullptr); | |
| 5684 | const int status = | ||
| 5685 | 29 | join_read_const_table(tab, positions + const_tables - 1); | |
| 5686 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (status > 0) |
| 5687 | ✗ | return true; | |
| 5688 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 14 times.
|
29 | else if (status == 0) |
| 5689 | 15 | found_const_table_map |= tl->map(); | |
| 5690 | 29 | continue; | |
| 5691 | 29 | } | |
| 5692 | } | ||
| 5693 | |||
| 5694 | // Check if table can be read by key or table only uses const refs | ||
| 5695 | |||
| 5696 |
2/2✓ Branch 0 taken 2191649 times.
✓ Branch 1 taken 1311149 times.
|
3502820 | if ((keyuse = tab->keyuse())) { |
| 5697 |
2/2✓ Branch 0 taken 3473616 times.
✓ Branch 1 taken 2106287 times.
|
5579903 | while (keyuse->table_ref == tl) { |
| 5698 | 3473616 | Key_use *const start_keyuse = keyuse; | |
| 5699 | 3473616 | const uint key = keyuse->key; | |
| 5700 | 3473616 | tab->keys().set_bit(key); // QQ: remove this ? | |
| 5701 | |||
| 5702 | 3473625 | table_map refs = 0; | |
| 5703 |
2/4✓ Branch 0 taken 3473631 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3473630 times.
✗ Branch 3 not taken.
|
3473625 | Key_map const_ref, eq_part; |
| 5704 | do { | ||
| 5705 |
7/8✓ Branch 0 taken 4655097 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4653031 times.
✓ Branch 3 taken 2066 times.
✓ Branch 4 taken 4652783 times.
✓ Branch 5 taken 248 times.
✓ Branch 6 taken 4652784 times.
✓ Branch 7 taken 2313 times.
|
4655096 | if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize) { |
| 5706 |
2/2✓ Branch 0 taken 873263 times.
✓ Branch 1 taken 3779521 times.
|
4652784 | if (!((~found_const_table_map) & keyuse->used_tables)) |
| 5707 | 873263 | const_ref.set_bit(keyuse->keypart); | |
| 5708 | else | ||
| 5709 | 3779521 | refs |= keyuse->used_tables; | |
| 5710 | 4652785 | eq_part.set_bit(keyuse->keypart); | |
| 5711 | } | ||
| 5712 | 4655089 | keyuse++; | |
| 5713 |
4/4✓ Branch 0 taken 2463835 times.
✓ Branch 1 taken 2191254 times.
✓ Branch 2 taken 1181466 times.
✓ Branch 3 taken 1282369 times.
|
4655089 | } while (keyuse->table_ref == tl && keyuse->key == key); |
| 5714 | |||
| 5715 | /* | ||
| 5716 | Extract const tables with proper key dependencies. | ||
| 5717 | Exclude tables that | ||
| 5718 | 1. are full-text searched, or | ||
| 5719 | 2. are part of nested outer join, or | ||
| 5720 | 3. are part of semi-join, or | ||
| 5721 | 4. have an expensive outer join condition. | ||
| 5722 | 5. are blocked by handler for const table optimize. | ||
| 5723 | 6. are not going to be used, typically because they are streamed | ||
| 5724 | instead of materialized | ||
| 5725 | (see Query_expression::can_materialize_directly_into_result()). | ||
| 5726 | */ | ||
| 5727 | 3473623 | if (eq_part.is_prefix(table->key_info[key].user_defined_key_parts) && | |
| 5728 |
4/4✓ Branch 0 taken 2411416 times.
✓ Branch 1 taken 47 times.
✓ Branch 2 taken 2411385 times.
✓ Branch 3 taken 38 times.
|
4822880 | !tl->is_fulltext_searched() && // 1 |
| 5729 | 2411416 | !tl->outer_join_nest() && // 2 | |
| 5730 |
6/6✓ Branch 0 taken 5617 times.
✓ Branch 1 taken 2405768 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5616 times.
✓ Branch 4 taken 76 times.
✓ Branch 5 taken 2405692 times.
|
4817153 | !(tl->embedding && tl->embedding->is_sj_or_aj_nest()) && // 3 |
| 5731 |
2/4✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
|
2405845 | !(tab->join_cond() && tab->join_cond()->is_expensive()) && // 4 |
| 5732 |
7/8✓ Branch 0 taken 2411457 times.
✓ Branch 1 taken 1062163 times.
✓ Branch 2 taken 2405761 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2405026 times.
✓ Branch 5 taken 731 times.
✓ Branch 6 taken 2405026 times.
✓ Branch 7 taken 1068593 times.
|
8290846 | !(table->file->ha_table_flags() & HA_BLOCK_CONST_TABLE) && // 5 |
| 5733 | 2405761 | table->is_created()) { // 6 | |
| 5734 |
2/2✓ Branch 0 taken 1885431 times.
✓ Branch 1 taken 519595 times.
|
2405026 | if (table->key_info[key].flags & HA_NOSAME) { |
| 5735 |
2/2✓ Branch 0 taken 85368 times.
✓ Branch 1 taken 1800064 times.
|
1885431 | if (const_ref == eq_part) { // Found everything for ref. |
| 5736 | 85368 | ref_changed = true; | |
| 5737 |
1/2✓ Branch 0 taken 85368 times.
✗ Branch 1 not taken.
|
85368 | mark_const_table(tab, start_keyuse); |
| 5738 |
3/4✓ Branch 0 taken 85368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 85366 times.
|
85368 | if (create_ref_for_key(this, tab, start_keyuse, |
| 5739 | found_const_table_map)) | ||
| 5740 | 87 | return true; | |
| 5741 | const int status = | ||
| 5742 |
1/2✓ Branch 0 taken 85366 times.
✗ Branch 1 not taken.
|
85366 | join_read_const_table(tab, positions + const_tables - 1); |
| 5743 |
2/2✓ Branch 0 taken 85 times.
✓ Branch 1 taken 85281 times.
|
85366 | if (status > 0) |
| 5744 | 85 | return true; | |
| 5745 |
2/2✓ Branch 0 taken 82457 times.
✓ Branch 1 taken 2824 times.
|
85281 | else if (status == 0) |
| 5746 | 82457 | found_const_table_map |= tl->map(); | |
| 5747 | 85281 | break; | |
| 5748 | } else | ||
| 5749 | 1800064 | found_ref |= refs; // Table is const if all refs are const | |
| 5750 |
2/2✓ Branch 0 taken 73713 times.
✓ Branch 1 taken 445883 times.
|
519595 | } else if (const_ref == eq_part) |
| 5751 | 73713 | tab->const_keys.set_bit(key); | |
| 5752 | } | ||
| 5753 | } | ||
| 5754 | } | ||
| 5755 | } | ||
| 5756 | } while | ||
| 5757 | /* | ||
| 5758 | A new const table appeared, that is referenced by others, so re-check | ||
| 5759 | others: | ||
| 5760 | */ | ||
| 5761 |
4/4✓ Branch 0 taken 654 times.
✓ Branch 1 taken 1907498 times.
✓ Branch 2 taken 82 times.
✓ Branch 3 taken 572 times.
|
1908152 | ((const_table_map & found_ref) && ref_changed); |
| 5762 | |||
| 5763 | 1908070 | return false; | |
| 5764 | } | ||
| 5765 | |||
| 5766 | /** | ||
| 5767 | Update info on indexes that can be used for search lookups as | ||
| 5768 | reading const tables may has added new sargable predicates. | ||
| 5769 | */ | ||
| 5770 | |||
| 5771 | 90395 | void JOIN::update_sargable_from_const(SARGABLE_PARAM *sargables) { | |
| 5772 |
2/2✓ Branch 0 taken 80 times.
✓ Branch 1 taken 90395 times.
|
90475 | for (; sargables->field; sargables++) { |
| 5773 | 80 | Field *const field = sargables->field; | |
| 5774 | 80 | JOIN_TAB *const tab = field->table->reginfo.join_tab; | |
| 5775 | 80 | Key_map possible_keys = field->key_start; | |
| 5776 | 80 | possible_keys.intersect(field->table->keys_in_use_for_query); | |
| 5777 | 80 | bool is_const = true; | |
| 5778 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 80 times.
|
196 | for (uint j = 0; j < sargables->num_values; j++) |
| 5779 |
1/2✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
|
116 | is_const &= sargables->arg_value[j]->const_item(); |
| 5780 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 28 times.
|
80 | if (is_const) { |
| 5781 | 52 | tab->const_keys.merge(possible_keys); | |
| 5782 | 52 | tab->keys().merge(possible_keys); | |
| 5783 | } | ||
| 5784 | } | ||
| 5785 | 90395 | } | |
| 5786 | |||
| 5787 | 3828604 | double find_worst_seeks(const TABLE *table, double num_rows, | |
| 5788 | double table_scan_cost) { | ||
| 5789 | /* | ||
| 5790 | Set a max value for the cost of seek operations we can expect | ||
| 5791 | when using key lookup. This can't be too high as otherwise we | ||
| 5792 | are likely to use table scan. | ||
| 5793 | */ | ||
| 5794 | double worst_seeks = | ||
| 5795 |
1/2✓ Branch 0 taken 3828621 times.
✗ Branch 1 not taken.
|
3828604 | min(table->file->worst_seek_times(num_rows / 10), table_scan_cost * 3); |
| 5796 |
1/2✓ Branch 0 taken 3828623 times.
✗ Branch 1 not taken.
|
3828620 | const double min_worst_seek = table->file->worst_seek_times(2.0); |
| 5797 | 3828623 | return std::max(worst_seeks, min_worst_seek); // Fix for small tables | |
| 5798 | } | ||
| 5799 | |||
| 5800 | /** | ||
| 5801 | Estimate the number of matched rows for each joined table. | ||
| 5802 | Set up range scan for tables that have proper predicates. | ||
| 5803 | |||
| 5804 | @returns false if success, true if error | ||
| 5805 | */ | ||
| 5806 | |||
| 5807 | 1912010 | bool JOIN::estimate_rowcount() { | |
| 5808 | 1912010 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 5809 |
1/2✓ Branch 0 taken 1912031 times.
✗ Branch 1 not taken.
|
1912010 | Opt_trace_object trace_wrapper(trace); |
| 5810 |
1/2✓ Branch 0 taken 1912030 times.
✗ Branch 1 not taken.
|
1912031 | Opt_trace_array trace_records(trace, "rows_estimation"); |
| 5811 | |||
| 5812 | 1912030 | JOIN_TAB *const tab_end = join_tab + tables; | |
| 5813 |
2/2✓ Branch 0 taken 3928482 times.
✓ Branch 1 taken 1912053 times.
|
5840535 | for (JOIN_TAB *tab = join_tab; tab < tab_end; tab++) { |
| 5814 |
1/2✓ Branch 0 taken 3928498 times.
✗ Branch 1 not taken.
|
3928482 | Opt_trace_object trace_table(trace); |
| 5815 |
1/2✓ Branch 0 taken 3928496 times.
✗ Branch 1 not taken.
|
3928498 | trace_table.add_utf8_table(tab->table_ref); |
| 5816 |
6/6✓ Branch 0 taken 3913943 times.
✓ Branch 1 taken 14560 times.
✓ Branch 2 taken 85324 times.
✓ Branch 3 taken 3828616 times.
✓ Branch 4 taken 99884 times.
✓ Branch 5 taken 3828616 times.
|
3928496 | if (tab->type() == JT_SYSTEM || tab->type() == JT_CONST) { |
| 5817 |
1/2✓ Branch 0 taken 99884 times.
✗ Branch 1 not taken.
|
99884 | trace_table.add("rows", 1) |
| 5818 |
1/2✓ Branch 0 taken 99884 times.
✗ Branch 1 not taken.
|
99884 | .add("cost", 1) |
| 5819 |
3/4✓ Branch 0 taken 14560 times.
✓ Branch 1 taken 85323 times.
✓ Branch 2 taken 99884 times.
✗ Branch 3 not taken.
|
99883 | .add_alnum("table_type", |
| 5820 | 99884 | (tab->type() == JT_SYSTEM) ? "system" : "const") | |
| 5821 |
1/2✓ Branch 0 taken 99884 times.
✗ Branch 1 not taken.
|
99884 | .add("empty", tab->table()->has_null_row()); |
| 5822 | |||
| 5823 | // Only one matching row and one block to read | ||
| 5824 | 99884 | tab->set_records(tab->found_records = 1); | |
| 5825 |
1/2✓ Branch 0 taken 99884 times.
✗ Branch 1 not taken.
|
99884 | tab->worst_seeks = tab->table()->file->worst_seek_times(1.0); |
| 5826 | 99884 | tab->read_time = tab->worst_seeks; | |
| 5827 | 99884 | continue; | |
| 5828 | } | ||
| 5829 | // Approximate number of found rows and cost to read them | ||
| 5830 | 3828616 | tab->set_records(tab->found_records = tab->table()->file->stats.records); | |
| 5831 |
1/2✓ Branch 0 taken 3828607 times.
✗ Branch 1 not taken.
|
3828600 | const Cost_estimate table_scan_time = tab->table()->file->table_scan_cost(); |
| 5832 | 3828607 | tab->read_time = table_scan_time.total_cost(); | |
| 5833 | |||
| 5834 | 3828620 | tab->worst_seeks = | |
| 5835 |
1/2✓ Branch 0 taken 3828620 times.
✗ Branch 1 not taken.
|
3828612 | find_worst_seeks(tab->table(), tab->found_records, tab->read_time); |
| 5836 | |||
| 5837 | /* | ||
| 5838 | Add to tab->const_keys the indexes for which all group fields or | ||
| 5839 | all select distinct fields participate in one index. | ||
| 5840 | Add to tab->skip_scan_keys indexes which can be used for skip | ||
| 5841 | scan access if no aggregates are present. | ||
| 5842 | */ | ||
| 5843 |
1/2✓ Branch 0 taken 3828606 times.
✗ Branch 1 not taken.
|
3828620 | add_loose_index_scan_and_skip_scan_keys(this, tab); |
| 5844 | |||
| 5845 | /* | ||
| 5846 | Perform range analysis if there are keys it could use (1). | ||
| 5847 | Don't do range analysis if on the inner side of an outer join (2). | ||
| 5848 | Do range analysis if on the inner side of a semi-join (3). | ||
| 5849 | */ | ||
| 5850 | 3828606 | TABLE_LIST *const tl = tab->table_ref; | |
| 5851 | 3828606 | if ((!tab->const_keys.is_clear_all() || | |
| 5852 |
6/6✓ Branch 0 taken 3293722 times.
✓ Branch 1 taken 534881 times.
✓ Branch 2 taken 22516 times.
✓ Branch 3 taken 3271216 times.
✓ Branch 4 taken 556993 times.
✓ Branch 5 taken 3271620 times.
|
4386000 | !tab->skip_scan_keys.is_clear_all()) && // (1) |
| 5853 |
2/2✓ Branch 0 taken 603 times.
✓ Branch 1 taken 556794 times.
|
557397 | (!tl->embedding || // (2) |
| 5854 |
3/4✓ Branch 0 taken 603 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 199 times.
✓ Branch 3 taken 404 times.
|
603 | (tl->embedding && tl->embedding->is_sj_or_aj_nest()))) // (3) |
| 5855 | { | ||
| 5856 | /* | ||
| 5857 | This call fills tab->range_scan() with the best QUICK access method | ||
| 5858 | possible for this table, and only if it's better than table scan. | ||
| 5859 | It also fills tab->needed_reg. | ||
| 5860 | */ | ||
| 5861 |
1/2✓ Branch 0 taken 556993 times.
✗ Branch 1 not taken.
|
556993 | ha_rows records = get_quick_record_count(thd, tab, row_limit); |
| 5862 | |||
| 5863 |
5/8✓ Branch 0 taken 1095 times.
✓ Branch 1 taken 555898 times.
✓ Branch 2 taken 1095 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1095 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 556993 times.
|
556993 | if (records == 0 && thd->is_error()) return true; |
| 5864 | |||
| 5865 | /* | ||
| 5866 | Check for "impossible range", but make sure that we do not attempt | ||
| 5867 | to mark semi-joined tables as "const" (only semi-joined tables that | ||
| 5868 | are functionally dependent can be marked "const", and subsequently | ||
| 5869 | pulled out of their semi-join nests). | ||
| 5870 | */ | ||
| 5871 |
5/6✓ Branch 0 taken 1095 times.
✓ Branch 1 taken 555898 times.
✓ Branch 2 taken 1095 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1085 times.
✓ Branch 5 taken 555908 times.
|
558088 | if (records == 0 && tab->table()->reginfo.impossible_range && |
| 5872 |
3/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1085 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
|
1095 | (!(tl->embedding && tl->embedding->is_sj_or_aj_nest()))) { |
| 5873 | /* | ||
| 5874 | Impossible WHERE condition or join condition | ||
| 5875 | In case of join cond, mark that one empty NULL row is matched. | ||
| 5876 | In case of WHERE, don't set found_const_table_map to get the | ||
| 5877 | caller to abort with a zero row result. | ||
| 5878 | */ | ||
| 5879 |
1/2✓ Branch 0 taken 1085 times.
✗ Branch 1 not taken.
|
1085 | mark_const_table(tab, nullptr); |
| 5880 | 1085 | tab->set_type(JT_CONST); // Override setting made in mark_const_table() | |
| 5881 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1081 times.
|
1085 | if (tab->join_cond()) { |
| 5882 | // Generate an empty row | ||
| 5883 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | trace_table.add("returning_empty_null_row", true) |
| 5884 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | .add_alnum("cause", "impossible_on_condition"); |
| 5885 | 4 | found_const_table_map |= tl->map(); | |
| 5886 | 4 | tab->table()->set_null_row(); // All fields are NULL | |
| 5887 | } else { | ||
| 5888 |
2/4✓ Branch 0 taken 1081 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1081 times.
✗ Branch 3 not taken.
|
1081 | trace_table.add("rows", 0).add_alnum("cause", |
| 5889 | "impossible_where_condition"); | ||
| 5890 | } | ||
| 5891 | } | ||
| 5892 |
2/2✓ Branch 0 taken 250484 times.
✓ Branch 1 taken 306509 times.
|
556993 | if (records != HA_POS_ERROR) { |
| 5893 | 250484 | tab->found_records = records; | |
| 5894 |
2/2✓ Branch 0 taken 249378 times.
✓ Branch 1 taken 1106 times.
|
250484 | tab->read_time = tab->range_scan() ? tab->range_scan()->cost : 0.0; |
| 5895 | } | ||
| 5896 | } else { | ||
| 5897 |
1/2✓ Branch 0 taken 3271605 times.
✗ Branch 1 not taken.
|
6543245 | Opt_trace_object(trace, "table_scan") |
| 5898 |
1/2✓ Branch 0 taken 3271624 times.
✗ Branch 1 not taken.
|
3271605 | .add("rows", tab->found_records) |
| 5899 |
1/2✓ Branch 0 taken 3271625 times.
✗ Branch 1 not taken.
|
3271624 | .add("cost", tab->read_time); |
| 5900 | } | ||
| 5901 |
2/3✓ Branch 0 taken 3828622 times.
✓ Branch 1 taken 99883 times.
✗ Branch 2 not taken.
|
3928506 | } |
| 5902 | |||
| 5903 | 1912053 | return false; | |
| 5904 | 1912052 | } | |
| 5905 | |||
| 5906 | /** | ||
| 5907 | Set semi-join embedding join nest pointers. | ||
| 5908 | |||
| 5909 | Set pointer to embedding semi-join nest for all semi-joined tables. | ||
| 5910 | This is the closest semi-join or anti-join nest. | ||
| 5911 | Note that this must be done for every table inside all semi-join nests, | ||
| 5912 | even for tables within outer join nests embedded in semi-join nests. | ||
| 5913 | A table can never be part of multiple semi-join nests, hence no | ||
| 5914 | ambiguities can ever occur. | ||
| 5915 | Note also that the pointer is not set for TABLE_LIST objects that | ||
| 5916 | are outer join nests within semi-join nests. | ||
| 5917 | */ | ||
| 5918 | |||
| 5919 | 2721 | void JOIN::set_semijoin_embedding() { | |
| 5920 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2721 times.
|
2721 | assert(!query_block->sj_nests.empty()); |
| 5921 | |||
| 5922 | 2721 | JOIN_TAB *const tab_end = join_tab + primary_tables; | |
| 5923 | |||
| 5924 |
2/2✓ Branch 0 taken 15794 times.
✓ Branch 1 taken 2721 times.
|
18515 | for (JOIN_TAB *tab = join_tab; tab < tab_end; tab++) { |
| 5925 | 15794 | tab->emb_sj_nest = nullptr; | |
| 5926 |
2/2✓ Branch 0 taken 10536 times.
✓ Branch 1 taken 15794 times.
|
26330 | for (TABLE_LIST *tl = tab->table_ref; tl->embedding; tl = tl->embedding) { |
| 5927 |
2/2✓ Branch 0 taken 10400 times.
✓ Branch 1 taken 136 times.
|
10536 | if (tl->embedding->is_sj_or_aj_nest()) { |
| 5928 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10400 times.
|
10400 | assert(!tab->emb_sj_nest); |
| 5929 | 10400 | tab->emb_sj_nest = tl->embedding; | |
| 5930 | // Let the up-walk continue, to assert there's no AJ/SJ nest above. | ||
| 5931 | } | ||
| 5932 | } | ||
| 5933 | } | ||
| 5934 | 2721 | } | |
| 5935 | |||
| 5936 | /** | ||
| 5937 | @brief Check if semijoin's compared types allow materialization. | ||
| 5938 | |||
| 5939 | @param[in,out] sj_nest Semi-join nest containing information about correlated | ||
| 5940 | expressions. Set nested_join->sjm.scan_allowed to true if | ||
| 5941 | MaterializeScan strategy allowed. Set nested_join->sjm.lookup_allowed | ||
| 5942 | to true if MaterializeLookup strategy allowed | ||
| 5943 | |||
| 5944 | @details | ||
| 5945 | This is a temporary fix for BUG#36752. | ||
| 5946 | |||
| 5947 | There are two subquery materialization strategies for semijoin: | ||
| 5948 | |||
| 5949 | 1. Materialize and do index lookups in the materialized table. See | ||
| 5950 | BUG#36752 for description of restrictions we need to put on the | ||
| 5951 | compared expressions. | ||
| 5952 | |||
| 5953 | In addition, since indexes are not supported for BLOB columns, | ||
| 5954 | this strategy can not be used if any of the columns in the | ||
| 5955 | materialized table will be BLOB/GEOMETRY columns. (Note that | ||
| 5956 | also columns for non-BLOB values that may be greater in size | ||
| 5957 | than CONVERT_IF_BIGGER_TO_BLOB, will be represented as BLOB | ||
| 5958 | columns.) | ||
| 5959 | |||
| 5960 | 2. Materialize and then do a full scan of the materialized table. | ||
| 5961 | The same criteria as for MaterializeLookup are applied, except that | ||
| 5962 | BLOB/GEOMETRY columns are allowed. | ||
| 5963 | */ | ||
| 5964 | |||
| 5965 | 2576 | static void semijoin_types_allow_materialization(TABLE_LIST *sj_nest) { | |
| 5966 |
1/2✓ Branch 0 taken 2576 times.
✗ Branch 1 not taken.
|
2576 | DBUG_TRACE; |
| 5967 | |||
| 5968 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2576 times.
|
2576 | assert(sj_nest->nested_join->sj_outer_exprs.size() == |
| 5969 | sj_nest->nested_join->sj_inner_exprs.size()); | ||
| 5970 | |||
| 5971 |
3/6✓ Branch 0 taken 2576 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2576 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2576 times.
|
5152 | if (sj_nest->nested_join->sj_outer_exprs.size() > MAX_REF_PARTS || |
| 5972 | 2576 | sj_nest->nested_join->sj_outer_exprs.size() == 0) { | |
| 5973 | // building an index is impossible | ||
| 5974 | ✗ | sj_nest->nested_join->sjm.scan_allowed = false; | |
| 5975 | ✗ | sj_nest->nested_join->sjm.lookup_allowed = false; | |
| 5976 | ✗ | return; | |
| 5977 | } | ||
| 5978 | |||
| 5979 | 2576 | sj_nest->nested_join->sjm.scan_allowed = true; | |
| 5980 | 2576 | sj_nest->nested_join->sjm.lookup_allowed = true; | |
| 5981 | |||
| 5982 | 2576 | bool blobs_involved = false; | |
| 5983 | 2576 | uint total_lookup_index_length = 0; | |
| 5984 | uint max_key_length, max_key_part_length, max_key_parts; | ||
| 5985 | /* | ||
| 5986 | Maximum lengths for keys and key parts that are supported by | ||
| 5987 | the temporary table storage engine(s). | ||
| 5988 | */ | ||
| 5989 |
1/2✓ Branch 0 taken 2576 times.
✗ Branch 1 not taken.
|
2576 | get_max_key_and_part_length(&max_key_length, &max_key_part_length, |
| 5990 | &max_key_parts); | ||
| 5991 |
1/2✓ Branch 0 taken 2576 times.
✗ Branch 1 not taken.
|
2576 | auto it1 = sj_nest->nested_join->sj_outer_exprs.begin(); |
| 5992 |
1/2✓ Branch 0 taken 2576 times.
✗ Branch 1 not taken.
|
2576 | auto it2 = sj_nest->nested_join->sj_inner_exprs.begin(); |
| 5993 |
4/6✓ Branch 0 taken 4968 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4968 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2635 times.
✓ Branch 5 taken 2333 times.
|
7603 | while (it1 != sj_nest->nested_join->sj_outer_exprs.end() && |
| 5994 |
5/8✓ Branch 0 taken 2635 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2635 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2635 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2635 times.
✓ Branch 7 taken 2333 times.
|
7603 | it2 != sj_nest->nested_join->sj_inner_exprs.end()) { |
| 5995 |
2/4✓ Branch 0 taken 2635 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2635 times.
✗ Branch 3 not taken.
|
2635 | Item *outer = *it1++; |
| 5996 |
2/4✓ Branch 0 taken 2635 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2635 times.
✗ Branch 3 not taken.
|
2635 | Item *inner = *it2++; |
| 5997 |
4/8✓ Branch 0 taken 2635 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2635 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2635 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2635 times.
✗ Branch 7 not taken.
|
2635 | assert(outer->real_item() && inner->real_item()); |
| 5998 |
3/4✓ Branch 0 taken 2635 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 243 times.
✓ Branch 3 taken 2392 times.
|
2635 | if (!types_allow_materialization(outer, inner)) { |
| 5999 | 243 | sj_nest->nested_join->sjm.scan_allowed = false; | |
| 6000 | 243 | sj_nest->nested_join->sjm.lookup_allowed = false; | |
| 6001 | 243 | return; | |
| 6002 | } | ||
| 6003 |
1/2✓ Branch 0 taken 2392 times.
✗ Branch 1 not taken.
|
2392 | blobs_involved |= inner->is_blob_field(); |
| 6004 | |||
| 6005 | // Calculate the index length of materialized table | ||
| 6006 |
1/2✓ Branch 0 taken 2392 times.
✗ Branch 1 not taken.
|
2392 | const uint lookup_index_length = get_key_length_tmp_table(inner); |
| 6007 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2390 times.
|
2392 | if (lookup_index_length > max_key_part_length) |
| 6008 | 2 | sj_nest->nested_join->sjm.lookup_allowed = false; | |
| 6009 | 2392 | total_lookup_index_length += lookup_index_length; | |
| 6010 | } | ||
| 6011 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2331 times.
|
2333 | if (total_lookup_index_length > max_key_length) |
| 6012 | 2 | sj_nest->nested_join->sjm.lookup_allowed = false; | |
| 6013 | |||
| 6014 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2329 times.
|
2333 | if (blobs_involved) sj_nest->nested_join->sjm.lookup_allowed = false; |
| 6015 | |||
| 6016 |
3/8✓ Branch 0 taken 2333 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2333 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2333 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
2333 | DBUG_PRINT("info", ("semijoin_types_allow_materialization: ok, allowed")); |
| 6017 |
2/2✓ Branch 0 taken 2333 times.
✓ Branch 1 taken 243 times.
|
2576 | } |
| 6018 | |||
| 6019 | /** | ||
| 6020 | Index dive can be skipped if the following conditions are satisfied: | ||
| 6021 | F1) For a single table query: | ||
| 6022 | a) FORCE INDEX applies to a single index. | ||
| 6023 | b) No subquery is present. | ||
| 6024 | c) Fulltext Index is not involved. | ||
| 6025 | d) No GROUP-BY or DISTINCT clause. | ||
| 6026 | e) No ORDER-BY clause. | ||
| 6027 | |||
| 6028 | F2) Not applicable to multi-table query. | ||
| 6029 | |||
| 6030 | F3) This optimization is not applicable to EXPLAIN queries. | ||
| 6031 | |||
| 6032 | @param tab JOIN_TAB object. | ||
| 6033 | @param thd THD object. | ||
| 6034 | */ | ||
| 6035 | 556993 | static bool check_skip_records_in_range_qualification(JOIN_TAB *tab, THD *thd) { | |
| 6036 | 556993 | Query_block *select = thd->lex->current_query_block(); | |
| 6037 | 556993 | TABLE *table = tab->table(); | |
| 6038 |
2/2✓ Branch 0 taken 125178 times.
✓ Branch 1 taken 112 times.
|
125290 | return ((table->force_index && |
| 6039 |
2/2✓ Branch 0 taken 125172 times.
✓ Branch 1 taken 6 times.
|
250468 | table->keys_in_use_for_query.bits_set() == 1) && // F1.a |
| 6040 | 125178 | select->parent_lex->is_single_level_stmt() && // F1.b | |
| 6041 |
2/2✓ Branch 0 taken 125171 times.
✓ Branch 1 taken 1 times.
|
125172 | !select->has_ft_funcs() && // F1.c |
| 6042 |
4/4✓ Branch 0 taken 3537 times.
✓ Branch 1 taken 121634 times.
✓ Branch 2 taken 3531 times.
✓ Branch 3 taken 6 times.
|
125171 | (!select->is_grouped() && !select->is_distinct()) && // F1.d |
| 6043 |
4/4✓ Branch 0 taken 2125 times.
✓ Branch 1 taken 1406 times.
✓ Branch 2 taken 2087 times.
✓ Branch 3 taken 38 times.
|
5656 | !select->is_ordered() && // F1.e |
| 6044 |
2/2✓ Branch 0 taken 125290 times.
✓ Branch 1 taken 431703 times.
|
684408 | select->join_list->size() == 1 && // F2 |
| 6045 |
2/2✓ Branch 0 taken 1941 times.
✓ Branch 1 taken 146 times.
|
559080 | !thd->lex->is_explain()); // F3 |
| 6046 | } | ||
| 6047 | |||
| 6048 | /***************************************************************************** | ||
| 6049 | Create JOIN_TABS, make a guess about the table types, | ||
| 6050 | Approximate how many records will be used in each table | ||
| 6051 | *****************************************************************************/ | ||
| 6052 | |||
| 6053 | /** | ||
| 6054 | Returns estimated number of rows that could be fetched by given | ||
| 6055 | access method. | ||
| 6056 | |||
| 6057 | The function calls the range optimizer to estimate the cost of the | ||
| 6058 | cheapest QUICK_* index access method to scan one or several of the | ||
| 6059 | 'keys' using the conditions 'select->cond'. The range optimizer | ||
| 6060 | compares several different types of 'quick select' methods (range | ||
| 6061 | scan, index merge, loose index scan) and selects the cheapest one. | ||
| 6062 | |||
| 6063 | If the best index access method is cheaper than a table- and an index | ||
| 6064 | scan, then the range optimizer also constructs the corresponding | ||
| 6065 | QUICK_* object and assigns it to select->quick. In most cases this | ||
| 6066 | is the QUICK_* object used at later (optimization and execution) | ||
| 6067 | phases. | ||
| 6068 | |||
| 6069 | @param thd Session that runs the query. | ||
| 6070 | @param tab JOIN_TAB of source table. | ||
| 6071 | @param limit maximum number of rows to select. | ||
| 6072 | |||
| 6073 | @note | ||
| 6074 | In case of valid range, a RowIterator object will be constructed and | ||
| 6075 | saved in select->quick. | ||
| 6076 | |||
| 6077 | @return Estimated number of result rows selected from 'tab'. | ||
| 6078 | |||
| 6079 | @retval HA_POS_ERROR For derived tables/views or if an error occur. | ||
| 6080 | @retval 0 If impossible query (i.e. certainly no rows will be | ||
| 6081 | selected.) | ||
| 6082 | */ | ||
| 6083 | 556993 | static ha_rows get_quick_record_count(THD *thd, JOIN_TAB *tab, ha_rows limit) { | |
| 6084 |
1/2✓ Branch 0 taken 556993 times.
✗ Branch 1 not taken.
|
556993 | DBUG_TRACE; |
| 6085 | uchar buff[STACK_BUFF_ALLOC]; | ||
| 6086 |
2/4✓ Branch 0 taken 556993 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 556993 times.
|
556993 | if (check_stack_overrun(thd, STACK_MIN_SIZE, buff)) |
| 6087 | ✗ | return 0; // Fatal error flag is set | |
| 6088 | 556993 | TABLE_LIST *const tl = tab->table_ref; | |
| 6089 | 1113986 | tab->set_skip_records_in_range( | |
| 6090 |
1/2✓ Branch 0 taken 556993 times.
✗ Branch 1 not taken.
|
556993 | check_skip_records_in_range_qualification(tab, thd)); |
| 6091 | |||
| 6092 | // Derived tables aren't filled yet, so no stats are available. | ||
| 6093 |
2/2✓ Branch 0 taken 556622 times.
✓ Branch 1 taken 371 times.
|
556993 | if (!tl->uses_materialization()) { |
| 6094 | AccessPath *range_scan; | ||
| 6095 | 556622 | Key_map keys_to_use = tab->const_keys; | |
| 6096 | 556622 | keys_to_use.merge(tab->skip_scan_keys); | |
| 6097 | MEM_ROOT temp_mem_root(key_memory_test_quick_select_exec, | ||
| 6098 | 556622 | thd->variables.range_alloc_block_size); | |
| 6099 |
3/4✓ Branch 0 taken 89543 times.
✓ Branch 1 taken 467079 times.
✓ Branch 2 taken 556622 times.
✗ Branch 3 not taken.
|
1580323 | int error = test_quick_select( |
| 6100 | thd, thd->mem_root, &temp_mem_root, keys_to_use, 0, | ||
| 6101 | 0, // empty table_map | ||
| 6102 | limit, | ||
| 6103 | false, // don't force quick range | ||
| 6104 | 556622 | ORDER_NOT_RELEVANT, tab->table(), tab->skip_records_in_range(), | |
| 6105 | 556622 | tab->join_cond() ? tab->join_cond() : tab->join()->where_cond, | |
| 6106 | 556622 | &tab->needed_reg, tab->table()->force_index, tab->join()->query_block, | |
| 6107 | &range_scan); | ||
| 6108 | 556622 | tab->set_range_scan(range_scan); | |
| 6109 | |||
| 6110 |
2/2✓ Branch 0 taken 249371 times.
✓ Branch 1 taken 307251 times.
|
556622 | if (error == 1) return range_scan->num_output_rows; |
| 6111 |
2/2✓ Branch 0 taken 1095 times.
✓ Branch 1 taken 306156 times.
|
307251 | if (error == -1) { |
| 6112 | 1095 | tl->table->reginfo.impossible_range = true; | |
| 6113 | 1095 | return 0; | |
| 6114 | } | ||
| 6115 |
5/8✓ Branch 0 taken 306156 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 306156 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 306151 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
|
306156 | DBUG_PRINT("warning", ("Couldn't use record count on const keypart")); |
| 6116 |
8/10✓ Branch 0 taken 306156 times.
✓ Branch 1 taken 250466 times.
✓ Branch 2 taken 353 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 353 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 353 times.
✓ Branch 8 taken 18 times.
✓ Branch 9 taken 353 times.
|
556993 | } else if (tl->is_table_function() || tl->materializable_is_const()) { |
| 6117 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | tl->fetch_number_of_rows(); |
| 6118 | 18 | return tl->table->file->stats.records; | |
| 6119 | } | ||
| 6120 | 306509 | return HA_POS_ERROR; | |
| 6121 | 556993 | } | |
| 6122 | |||
| 6123 | /* | ||
| 6124 | Get estimated record length for semi-join materialization temptable | ||
| 6125 | |||
| 6126 | SYNOPSIS | ||
| 6127 | get_tmp_table_rec_length() | ||
| 6128 | items IN subquery's select list. | ||
| 6129 | |||
| 6130 | DESCRIPTION | ||
| 6131 | Calculate estimated record length for semi-join materialization | ||
| 6132 | temptable. It's an estimate because we don't follow every bit of | ||
| 6133 | create_tmp_table()'s logic. This isn't necessary as the return value of | ||
| 6134 | this function is used only for cost calculations. | ||
| 6135 | |||
| 6136 | RETURN | ||
| 6137 | Length of the temptable record, in bytes | ||
| 6138 | */ | ||
| 6139 | |||
| 6140 | 2635 | static uint get_tmp_table_rec_length(const mem_root_deque<Item *> &items) { | |
| 6141 | 2635 | uint len = 0; | |
| 6142 |
8/14✓ Branch 0 taken 2635 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2635 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2635 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2706 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2706 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5341 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2706 times.
✓ Branch 13 taken 2635 times.
|
5341 | for (Item *item : VisibleFields(items)) { |
| 6143 |
5/7✓ Branch 0 taken 2706 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 1544 times.
✓ Branch 4 taken 1094 times.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
|
2706 | switch (item->result_type()) { |
| 6144 | 63 | case REAL_RESULT: | |
| 6145 | 63 | len += sizeof(double); | |
| 6146 | 63 | break; | |
| 6147 | 1544 | case INT_RESULT: | |
| 6148 |
2/2✓ Branch 0 taken 1504 times.
✓ Branch 1 taken 40 times.
|
1544 | if (item->max_length >= (MY_INT32_NUM_DECIMAL_DIGITS - 1)) |
| 6149 | 1504 | len += 8; | |
| 6150 | else | ||
| 6151 | 40 | len += 4; | |
| 6152 | 1544 | break; | |
| 6153 | 1094 | case STRING_RESULT: | |
| 6154 | /* DATE/TIME and GEOMETRY fields have STRING_RESULT result type. */ | ||
| 6155 |
5/6✓ Branch 0 taken 1058 times.
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1058 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 1058 times.
|
1094 | if (item->is_temporal() || item->data_type() == MYSQL_TYPE_GEOMETRY) |
| 6156 | 36 | len += 8; | |
| 6157 | else | ||
| 6158 | 1058 | len += item->max_length; | |
| 6159 | 1094 | break; | |
| 6160 | 5 | case DECIMAL_RESULT: | |
| 6161 | 5 | len += 10; | |
| 6162 | 5 | break; | |
| 6163 | ✗ | case ROW_RESULT: | |
| 6164 | default: | ||
| 6165 | ✗ | assert(0); /* purecov: deadcode */ | |
| 6166 | break; | ||
| 6167 | } | ||
| 6168 | } | ||
| 6169 | 2635 | return len; | |
| 6170 | } | ||
| 6171 | |||
| 6172 | /** | ||
| 6173 | Writes to the optimizer trace information about dependencies between | ||
| 6174 | tables. | ||
| 6175 | @param trace optimizer trace | ||
| 6176 | @param join_tabs all JOIN_TABs of the join | ||
| 6177 | @param table_count how many JOIN_TABs in the 'join_tabs' array | ||
| 6178 | */ | ||
| 6179 | 2702 | static void trace_table_dependencies(Opt_trace_context *trace, | |
| 6180 | JOIN_TAB *join_tabs, uint table_count) { | ||
| 6181 |
1/2✓ Branch 0 taken 2702 times.
✗ Branch 1 not taken.
|
2702 | Opt_trace_object trace_wrapper(trace); |
| 6182 |
1/2✓ Branch 0 taken 2702 times.
✗ Branch 1 not taken.
|
2702 | Opt_trace_array trace_dep(trace, "table_dependencies"); |
| 6183 |
2/2✓ Branch 0 taken 3197 times.
✓ Branch 1 taken 2702 times.
|
5899 | for (uint i = 0; i < table_count; i++) { |
| 6184 | 3197 | TABLE_LIST *table_ref = join_tabs[i].table_ref; | |
| 6185 |
1/2✓ Branch 0 taken 3197 times.
✗ Branch 1 not taken.
|
3197 | Opt_trace_object trace_one_table(trace); |
| 6186 |
2/4✓ Branch 0 taken 3197 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3197 times.
✗ Branch 3 not taken.
|
6394 | trace_one_table.add_utf8_table(table_ref).add( |
| 6187 | 3197 | "row_may_be_null", table_ref->table->is_nullable()); | |
| 6188 | 3197 | const table_map map = table_ref->map(); | |
| 6189 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3197 times.
|
3197 | assert(map < (1ULL << table_count)); |
| 6190 |
1/2✓ Branch 0 taken 3955 times.
✗ Branch 1 not taken.
|
3955 | for (uint j = 0; j < table_count; j++) { |
| 6191 |
2/2✓ Branch 0 taken 3197 times.
✓ Branch 1 taken 758 times.
|
3955 | if (map & (1ULL << j)) { |
| 6192 |
1/2✓ Branch 0 taken 3197 times.
✗ Branch 1 not taken.
|
3197 | trace_one_table.add("map_bit", j); |
| 6193 | 3197 | break; | |
| 6194 | } | ||
| 6195 | } | ||
| 6196 |
1/2✓ Branch 0 taken 3197 times.
✗ Branch 1 not taken.
|
3197 | Opt_trace_array depends_on(trace, "depends_on_map_bits"); |
| 6197 | static_assert(sizeof(table_ref->map()) <= 64, | ||
| 6198 | "RAND_TABLE_BIT may be in join_tabs[i].dependent, so we test " | ||
| 6199 | "all 64 bits."); | ||
| 6200 |
2/2✓ Branch 0 taken 204608 times.
✓ Branch 1 taken 3197 times.
|
207805 | for (uint j = 0; j < 64; j++) { |
| 6201 |
3/4✓ Branch 0 taken 300 times.
✓ Branch 1 taken 204308 times.
✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
|
204608 | if (join_tabs[i].dependent & (1ULL << j)) depends_on.add(j); |
| 6202 | } | ||
| 6203 | 3197 | } | |
| 6204 | 2702 | } | |
| 6205 | |||
| 6206 | /** | ||
| 6207 | Add to join_tab[i]->condition() "table.field IS NOT NULL" conditions | ||
| 6208 | we've inferred from ref/eq_ref access performed. | ||
| 6209 | |||
| 6210 | This function is a part of "Early NULL-values filtering for ref access" | ||
| 6211 | optimization. | ||
| 6212 | |||
| 6213 | Example of this optimization: | ||
| 6214 | For query SELECT * FROM t1,t2 WHERE t2.key=t1.field @n | ||
| 6215 | and plan " any-access(t1), ref(t2.key=t1.field) " @n | ||
| 6216 | add "t1.field IS NOT NULL" to t1's table condition. @n | ||
| 6217 | |||
| 6218 | Description of the optimization: | ||
| 6219 | |||
| 6220 | We look through equalities chosen to perform ref/eq_ref access, | ||
| 6221 | pick equalities that have form "tbl.part_of_key = othertbl.field" | ||
| 6222 | (where othertbl is a non-const table and othertbl.field may be NULL) | ||
| 6223 | and add them to conditions on corresponding tables (othertbl in this | ||
| 6224 | example). | ||
| 6225 | |||
| 6226 | Exception from that is the case when referred_tab->join != join. | ||
| 6227 | I.e. don't add NOT NULL constraints from any embedded subquery. | ||
| 6228 | Consider this query: | ||
| 6229 | @code | ||
| 6230 | SELECT A.f2 FROM t1 LEFT JOIN t2 A ON A.f2 = f1 | ||
| 6231 | WHERE A.f3=(SELECT MIN(f3) FROM t2 C WHERE A.f4 = C.f4) OR A.f3 IS NULL; | ||
| 6232 | @endcode | ||
| 6233 | Here condition A.f3 IS NOT NULL is going to be added to the WHERE | ||
| 6234 | condition of the embedding query. | ||
| 6235 | Another example: | ||
| 6236 | SELECT * FROM t10, t11 WHERE (t10.a < 10 OR t10.a IS NULL) | ||
| 6237 | AND t11.b <=> t10.b AND (t11.a = (SELECT MAX(a) FROM t12 | ||
| 6238 | WHERE t12.b = t10.a )); | ||
| 6239 | Here condition t10.a IS NOT NULL is going to be added. | ||
| 6240 | In both cases addition of NOT NULL condition will erroneously reject | ||
| 6241 | some rows of the result set. | ||
| 6242 | referred_tab->join != join constraint would disallow such additions. | ||
| 6243 | |||
| 6244 | This optimization doesn't affect the choices that ref, range, or join | ||
| 6245 | optimizer make. This was intentional because this was added after 4.1 | ||
| 6246 | was GA. | ||
| 6247 | |||
| 6248 | Implementation overview | ||
| 6249 | 1. update_ref_and_keys() accumulates info about null-rejecting | ||
| 6250 | predicates in in Key_field::null_rejecting | ||
| 6251 | 1.1 add_key_part saves these to Key_use. | ||
| 6252 | 2. create_ref_for_key copies them to TABLE_REF. | ||
| 6253 | 3. add_not_null_conds adds "x IS NOT NULL" to join_tab->m_condition of | ||
| 6254 | appropriate JOIN_TAB members. | ||
| 6255 | |||
| 6256 | @returns false on success, true on error | ||
| 6257 | */ | ||
| 6258 | |||
| 6259 | 1903440 | static bool add_not_null_conds(JOIN *join) { | |
| 6260 |
1/2✓ Branch 0 taken 1903459 times.
✗ Branch 1 not taken.
|
1903440 | DBUG_TRACE; |
| 6261 |
4/6✓ Branch 0 taken 1903459 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1903458 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1903458 times.
✗ Branch 5 not taken.
|
1903459 | ASSERT_BEST_REF_IN_JOIN_ORDER(join); |
| 6262 |
2/2✓ Branch 0 taken 6384959 times.
✓ Branch 1 taken 1903477 times.
|
8288436 | for (uint i = join->const_tables; i < join->tables; i++) { |
| 6263 | 6384959 | JOIN_TAB *const tab = join->best_ref[i]; | |
| 6264 |
4/4✓ Branch 0 taken 4369119 times.
✓ Branch 1 taken 1544344 times.
✓ Branch 2 taken 128 times.
✓ Branch 3 taken 4368990 times.
|
16667535 | if ((tab->type() != JT_REF && tab->type() != JT_EQ_REF && |
| 6265 |
6/6✓ Branch 0 taken 5913458 times.
✓ Branch 1 taken 471508 times.
✓ Branch 2 taken 394830 times.
✓ Branch 3 taken 1621158 times.
✓ Branch 4 taken 4763821 times.
✓ Branch 5 taken 1621157 times.
|
17139063 | tab->type() != JT_REF_OR_NULL) || |
| 6266 | 2015980 | tab->table()->is_nullable()) { | |
| 6267 | 4763821 | continue; | |
| 6268 | } | ||
| 6269 |
2/2✓ Branch 0 taken 2133923 times.
✓ Branch 1 taken 1621157 times.
|
3755088 | for (uint keypart = 0; keypart < tab->ref().key_parts; keypart++) { |
| 6270 |
2/2✓ Branch 0 taken 1822027 times.
✓ Branch 1 taken 311902 times.
|
2133923 | if ((tab->ref().null_rejecting & ((key_part_map)1 << keypart)) == 0) { |
| 6271 | 1971175 | continue; | |
| 6272 | } | ||
| 6273 |
1/2✓ Branch 0 taken 311904 times.
✗ Branch 1 not taken.
|
311902 | Item *const item = tab->ref().items[keypart]->real_item(); |
| 6274 |
7/8✓ Branch 0 taken 311904 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 173215 times.
✓ Branch 3 taken 138689 times.
✓ Branch 4 taken 524 times.
✓ Branch 5 taken 172691 times.
✓ Branch 6 taken 139213 times.
✓ Branch 7 taken 172691 times.
|
311904 | if (item->type() != Item::FIELD_ITEM || !item->is_nullable()) continue; |
| 6275 | 172691 | Item_field *const not_null_item = down_cast<Item_field *>(item); | |
| 6276 | 172691 | JOIN_TAB *referred_tab = not_null_item->field->table->reginfo.join_tab; | |
| 6277 | /* | ||
| 6278 | For UPDATE queries such as: | ||
| 6279 | UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1); | ||
| 6280 | not_null_item is the t1.f1, but it's referred_tab is 0. | ||
| 6281 | */ | ||
| 6282 |
5/6✓ Branch 0 taken 172604 times.
✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 172604 times.
✓ Branch 4 taken 87 times.
✓ Branch 5 taken 172604 times.
|
172691 | if (referred_tab == nullptr || referred_tab->join() != join) continue; |
| 6283 | /* Skip if we already have a 'not null' predicate for 'item' */ | ||
| 6284 |
3/4✓ Branch 0 taken 172604 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9848 times.
✓ Branch 3 taken 162756 times.
|
172604 | if (has_not_null_predicate(referred_tab->condition(), not_null_item)) |
| 6285 | 9848 | continue; | |
| 6286 |
2/4✓ Branch 0 taken 162756 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 162756 times.
✗ Branch 3 not taken.
|
162756 | Item *notnull = new Item_func_isnotnull(not_null_item); |
| 6287 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 162756 times.
|
162756 | if (notnull == nullptr) return true; |
| 6288 | /* | ||
| 6289 | We need to do full fix_fields() call here in order to have correct | ||
| 6290 | notnull->const_item(). This is needed e.g. by test_quick_select | ||
| 6291 | when it is called from make_join_query_block after this function is | ||
| 6292 | called. | ||
| 6293 | */ | ||
| 6294 |
2/4✓ Branch 0 taken 162756 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 162756 times.
|
162756 | if (notnull->fix_fields(join->thd, ¬null)) return true; |
| 6295 |
2/6✓ Branch 0 taken 162756 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 162756 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
162756 | DBUG_EXECUTE("where", |
| 6296 | print_where(join->thd, notnull, referred_tab->table()->alias, | ||
| 6297 | QT_ORDINARY);); | ||
| 6298 |
1/2✓ Branch 0 taken 162756 times.
✗ Branch 1 not taken.
|
162756 | referred_tab->and_with_condition(notnull); |
| 6299 | } | ||
| 6300 | } | ||
| 6301 | 1903477 | return false; | |
| 6302 | 1903477 | } | |
| 6303 | |||
| 6304 | /** | ||
| 6305 | Check all existing AND'ed predicates in 'cond' for an existing | ||
| 6306 | 'is not null 'not_null_item''-predicate. | ||
| 6307 | |||
| 6308 | A condition consisting of multiple AND'ed terms is recursively | ||
| 6309 | decomposed in the search for the specified not null predicate. | ||
| 6310 | |||
| 6311 | @param cond Condition to be checked. | ||
| 6312 | @param not_null_item The item in: 'is not null 'item'' to search for | ||
| 6313 | |||
| 6314 | @return true if 'is not null 'not_null_item'' is a predicate | ||
| 6315 | in the specified 'cond'. | ||
| 6316 | */ | ||
| 6317 | 172948 | static bool has_not_null_predicate(Item *cond, Item_field *not_null_item) { | |
| 6318 |
2/2✓ Branch 0 taken 131943 times.
✓ Branch 1 taken 41005 times.
|
172948 | if (cond == nullptr) return false; |
| 6319 |
2/2✓ Branch 0 taken 40831 times.
✓ Branch 1 taken 174 times.
|
41005 | if (cond->type() == Item::FUNC_ITEM) { |
| 6320 | 40831 | Item_func *item_func = down_cast<Item_func *>(cond); | |
| 6321 | 40831 | const Item_func::Functype func_type = item_func->functype(); | |
| 6322 |
1/2✓ Branch 0 taken 40831 times.
✗ Branch 1 not taken.
|
81662 | return (func_type == Item_func::ISNOTNULL_FUNC && |
| 6323 |
2/2✓ Branch 0 taken 9848 times.
✓ Branch 1 taken 30983 times.
|
81662 | item_func->key_item() == not_null_item); |
| 6324 |
1/2✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
|
174 | } else if (cond->type() == Item::COND_ITEM) { |
| 6325 | 174 | Item_cond *item_cond = down_cast<Item_cond *>(cond); | |
| 6326 |
1/2✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
|
174 | if (item_cond->functype() == Item_func::COND_AND_FUNC) { |
| 6327 |
1/2✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
|
174 | List_iterator<Item> li(*item_cond->argument_list()); |
| 6328 | Item *item; | ||
| 6329 |
2/2✓ Branch 0 taken 344 times.
✓ Branch 1 taken 166 times.
|
510 | while ((item = li++)) { |
| 6330 |
3/4✓ Branch 0 taken 344 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 336 times.
|
344 | if (has_not_null_predicate(item, not_null_item)) return true; |
| 6331 | } | ||
| 6332 | } | ||
| 6333 | } | ||
| 6334 | 166 | return false; | |
| 6335 | } | ||
| 6336 | |||
| 6337 | /** | ||
| 6338 | Check if given expression only uses fields covered by index @a keyno in the | ||
| 6339 | table tbl. The expression can use any fields in any other tables. | ||
| 6340 | |||
| 6341 | The expression is guaranteed not to be AND or OR - those constructs are | ||
| 6342 | handled outside of this function. | ||
| 6343 | |||
| 6344 | Restrict some function types from being pushed down to storage engine: | ||
| 6345 | a) Don't push down the triggered conditions. Nested outer joins execution | ||
| 6346 | code may need to evaluate a condition several times (both triggered and | ||
| 6347 | untriggered). | ||
| 6348 | TODO: Consider cloning the triggered condition and using the copies for: | ||
| 6349 | 1. push the first copy down, to have most restrictive index condition | ||
| 6350 | possible. | ||
| 6351 | 2. Put the second copy into tab->m_condition. | ||
| 6352 | b) Stored functions contain a statement that might start new operations (like | ||
| 6353 | DML statements) from within the storage engine. This does not work against | ||
| 6354 | all SEs. | ||
| 6355 | c) Subqueries might contain nested subqueries and involve more tables. | ||
| 6356 | TODO: ROY: CHECK THIS | ||
| 6357 | d) Do not push down internal functions of type DD_INTERNAL_FUNC. When ICP is | ||
| 6358 | enabled, pushing internal functions to storage engine for evaluation will | ||
| 6359 | open data-dictionary tables. In InnoDB storage engine this will result in | ||
| 6360 | situation like recursive latching of same page by the same thread. To avoid | ||
| 6361 | such situation, internal functions of type DD_INTERNAL_FUNC are not pushed | ||
| 6362 | to storage engine for evaluation. | ||
| 6363 | |||
| 6364 | @param item Expression to check | ||
| 6365 | @param tbl The table having the index | ||
| 6366 | @param keyno The index number | ||
| 6367 | @param other_tbls_ok true <=> Fields of other non-const tables are allowed | ||
| 6368 | |||
| 6369 | @return false if No, true if Yes | ||
| 6370 | */ | ||
| 6371 | |||
| 6372 | 22365 | bool uses_index_fields_only(Item *item, TABLE *tbl, uint keyno, | |
| 6373 | bool other_tbls_ok) { | ||
| 6374 | // Restrictions b and c. | ||
| 6375 |
6/6✓ Branch 0 taken 22355 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 55 times.
✓ Branch 3 taken 22300 times.
✓ Branch 4 taken 65 times.
✓ Branch 5 taken 22300 times.
|
22365 | if (item->has_stored_program() || item->has_subquery()) return false; |
| 6376 | |||
| 6377 | // No table fields in const items | ||
| 6378 |
2/2✓ Branch 0 taken 5748 times.
✓ Branch 1 taken 16552 times.
|
22300 | if (item->const_for_execution()) return true; |
| 6379 | |||
| 6380 | 16552 | const Item::Type item_type = item->type(); | |
| 6381 | |||
| 6382 |
4/5✓ Branch 0 taken 8371 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8116 times.
✓ Branch 3 taken 33 times.
✓ Branch 4 taken 32 times.
|
16552 | switch (item_type) { |
| 6383 | 8371 | case Item::FUNC_ITEM: { | |
| 6384 | 8371 | Item_func *item_func = (Item_func *)item; | |
| 6385 | 8371 | const Item_func::Functype func_type = item_func->functype(); | |
| 6386 | |||
| 6387 |
3/4✓ Branch 0 taken 8236 times.
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8236 times.
|
8371 | if (func_type == Item_func::TRIG_COND_FUNC || // Restriction a. |
| 6388 | func_type == Item_func::DD_INTERNAL_FUNC) // Restriction d. | ||
| 6389 | 135 | return false; | |
| 6390 | |||
| 6391 | /* This is a function, apply condition recursively to arguments */ | ||
| 6392 |
2/2✓ Branch 0 taken 8232 times.
✓ Branch 1 taken 4 times.
|
8236 | if (item_func->argument_count() > 0) { |
| 6393 | Item **item_end = | ||
| 6394 | 8232 | (item_func->arguments()) + item_func->argument_count(); | |
| 6395 |
2/2✓ Branch 0 taken 14196 times.
✓ Branch 1 taken 5808 times.
|
20004 | for (Item **child = item_func->arguments(); child != item_end; |
| 6396 | child++) { | ||
| 6397 |
2/2✓ Branch 0 taken 2424 times.
✓ Branch 1 taken 11772 times.
|
14196 | if (!uses_index_fields_only(*child, tbl, keyno, other_tbls_ok)) |
| 6398 | 2424 | return false; | |
| 6399 | } | ||
| 6400 | } | ||
| 6401 | 5812 | return true; | |
| 6402 | } | ||
| 6403 | ✗ | case Item::COND_ITEM: { | |
| 6404 | /* | ||
| 6405 | This is a AND/OR condition. Regular AND/OR clauses are handled by | ||
| 6406 | make_cond_for_index() which will chop off the part that can be | ||
| 6407 | checked with index. This code is for handling non-top-level AND/ORs, | ||
| 6408 | e.g. func(x AND y). | ||
| 6409 | */ | ||
| 6410 | ✗ | List_iterator<Item> li(*((Item_cond *)item)->argument_list()); | |
| 6411 | Item *cond_item; | ||
| 6412 | ✗ | while ((cond_item = li++)) { | |
| 6413 | ✗ | if (!uses_index_fields_only(cond_item, tbl, keyno, other_tbls_ok)) | |
| 6414 | ✗ | return false; | |
| 6415 | } | ||
| 6416 | ✗ | return true; | |
| 6417 | } | ||
| 6418 | 8116 | case Item::FIELD_ITEM: { | |
| 6419 | 8116 | const Item_field *item_field = down_cast<const Item_field *>(item); | |
| 6420 |
2/2✓ Branch 0 taken 197 times.
✓ Branch 1 taken 7919 times.
|
8116 | if (item_field->field->table != tbl) return other_tbls_ok; |
| 6421 | /* | ||
| 6422 | The below is probably a repetition - the first part checks the | ||
| 6423 | other two, but let's play it safe: | ||
| 6424 | */ | ||
| 6425 | 7919 | return item_field->field->part_of_key.is_set(keyno) && | |
| 6426 |
3/4✓ Branch 0 taken 5576 times.
✓ Branch 1 taken 2343 times.
✓ Branch 2 taken 5576 times.
✗ Branch 3 not taken.
|
13495 | item_field->field->type() != MYSQL_TYPE_GEOMETRY && |
| 6427 |
1/2✓ Branch 0 taken 5576 times.
✗ Branch 1 not taken.
|
13495 | item_field->field->type() != MYSQL_TYPE_BLOB; |
| 6428 | } | ||
| 6429 | 33 | case Item::REF_ITEM: | |
| 6430 | 33 | return uses_index_fields_only(item->real_item(), tbl, keyno, | |
| 6431 | 33 | other_tbls_ok); | |
| 6432 | 32 | default: | |
| 6433 | 32 | return false; /* Play it safe, don't push unknown non-const items */ | |
| 6434 | } | ||
| 6435 | } | ||
| 6436 | |||
| 6437 | /** | ||
| 6438 | Optimize semi-join nests that could be run with sj-materialization | ||
| 6439 | |||
| 6440 | @param join The join to optimize semi-join nests for | ||
| 6441 | |||
| 6442 | @details | ||
| 6443 | Optimize each of the semi-join nests that can be run with | ||
| 6444 | materialization. For each of the nests, we | ||
| 6445 | - Generate the best join order for this "sub-join" and remember it; | ||
| 6446 | - Remember the sub-join execution cost (it's part of materialization | ||
| 6447 | cost); | ||
| 6448 | - Calculate other costs that will be incurred if we decide | ||
| 6449 | to use materialization strategy for this semi-join nest. | ||
| 6450 | |||
| 6451 | All obtained information is saved and will be used by the main join | ||
| 6452 | optimization pass. | ||
| 6453 | |||
| 6454 | @return false if successful, true if error | ||
| 6455 | */ | ||
| 6456 | |||
| 6457 | 2961 | static bool optimize_semijoin_nests_for_materialization(JOIN *join) { | |
| 6458 |
1/2✓ Branch 0 taken 2961 times.
✗ Branch 1 not taken.
|
2961 | DBUG_TRACE; |
| 6459 | 2961 | Opt_trace_context *const trace = &join->thd->opt_trace; | |
| 6460 | |||
| 6461 |
7/12✓ Branch 0 taken 2961 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2961 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2798 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2798 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5759 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2798 times.
✓ Branch 11 taken 2961 times.
|
5759 | for (TABLE_LIST *sj_nest : join->query_block->sj_nests) { |
| 6462 | /* As a precaution, reset pointers that were used in prior execution */ | ||
| 6463 | 2798 | sj_nest->nested_join->sjm.positions = nullptr; | |
| 6464 | |||
| 6465 | /* Calculate the cost of materialization if materialization is allowed. */ | ||
| 6466 |
2/2✓ Branch 0 taken 2656 times.
✓ Branch 1 taken 142 times.
|
2798 | if (sj_nest->nested_join->sj_enabled_strategies & |
| 6467 | OPTIMIZER_SWITCH_MATERIALIZATION) { | ||
| 6468 | /* A semi-join nest should not contain tables marked as const */ | ||
| 6469 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2656 times.
|
2656 | assert(!(sj_nest->sj_inner_tables & join->const_table_map)); |
| 6470 | |||
| 6471 |
1/2✓ Branch 0 taken 2656 times.
✗ Branch 1 not taken.
|
2656 | Opt_trace_object trace_wrapper(trace); |
| 6472 | Opt_trace_object trace_sjmat( | ||
| 6473 |
1/2✓ Branch 0 taken 2656 times.
✗ Branch 1 not taken.
|
2656 | trace, "execution_plan_for_potential_materialization"); |
| 6474 |
1/2✓ Branch 0 taken 2656 times.
✗ Branch 1 not taken.
|
2656 | Opt_trace_array trace_sjmat_steps(trace, "steps"); |
| 6475 | /* | ||
| 6476 | Try semijoin materialization if the semijoin is classified as | ||
| 6477 | non-trivially-correlated. | ||
| 6478 | */ | ||
| 6479 |
2/2✓ Branch 0 taken 80 times.
✓ Branch 1 taken 2576 times.
|
2656 | if (sj_nest->nested_join->sj_corr_tables) continue; |
| 6480 | /* | ||
| 6481 | Check whether data types allow execution with materialization. | ||
| 6482 | */ | ||
| 6483 |
1/2✓ Branch 0 taken 2576 times.
✗ Branch 1 not taken.
|
2576 | semijoin_types_allow_materialization(sj_nest); |
| 6484 | |||
| 6485 |
2/2✓ Branch 0 taken 243 times.
✓ Branch 1 taken 2333 times.
|
2576 | if (!sj_nest->nested_join->sjm.scan_allowed && |
| 6486 |
1/2✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
|
243 | !sj_nest->nested_join->sjm.lookup_allowed) |
| 6487 | 243 | continue; | |
| 6488 | |||
| 6489 |
3/6✓ Branch 0 taken 2333 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2333 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2333 times.
|
2333 | if (Optimize_table_order(join->thd, join, sj_nest).choose_table_order()) |
| 6490 | ✗ | return true; | |
| 6491 | 2333 | const uint n_tables = my_count_bits(sj_nest->sj_inner_tables); | |
| 6492 | 2333 | calculate_materialization_costs(join, sj_nest, n_tables, | |
| 6493 |
1/2✓ Branch 0 taken 2333 times.
✗ Branch 1 not taken.
|
2333 | &sj_nest->nested_join->sjm); |
| 6494 | /* | ||
| 6495 | Cost data is in sj_nest->nested_join->sjm. We also need to save the | ||
| 6496 | plan: | ||
| 6497 | */ | ||
| 6498 | 4666 | if (!(sj_nest->nested_join->sjm.positions = | |
| 6499 |
2/4✓ Branch 0 taken 2333 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2333 times.
|
2333 | (POSITION *)join->thd->alloc(sizeof(POSITION) * n_tables))) |
| 6500 | ✗ | return true; | |
| 6501 | 2333 | memcpy(sj_nest->nested_join->sjm.positions, | |
| 6502 | 2333 | join->best_positions + join->const_tables, | |
| 6503 | 2333 | sizeof(POSITION) * n_tables); | |
| 6504 |
6/9✓ Branch 0 taken 2333 times.
✓ Branch 1 taken 323 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2333 times.
✓ Branch 4 taken 323 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2333 times.
✓ Branch 7 taken 323 times.
✗ Branch 8 not taken.
|
3302 | } |
| 6505 | } | ||
| 6506 | 2961 | return false; | |
| 6507 | 2961 | } | |
| 6508 | |||
| 6509 | /* | ||
| 6510 | Check if table's Key_use elements have an eq_ref(outer_tables) candidate | ||
| 6511 | |||
| 6512 | SYNOPSIS | ||
| 6513 | find_eq_ref_candidate() | ||
| 6514 | tl Table to be checked | ||
| 6515 | sj_inner_tables Bitmap of inner tables. eq_ref(inner_table) doesn't | ||
| 6516 | count. | ||
| 6517 | |||
| 6518 | DESCRIPTION | ||
| 6519 | Check if table's Key_use elements have an eq_ref(outer_tables) candidate | ||
| 6520 | |||
| 6521 | TODO | ||
| 6522 | Check again if it is feasible to factor common parts with constant table | ||
| 6523 | search | ||
| 6524 | |||
| 6525 | RETURN | ||
| 6526 | true - There exists an eq_ref(outer-tables) candidate | ||
| 6527 | false - Otherwise | ||
| 6528 | */ | ||
| 6529 | |||
| 6530 | 6645 | static bool find_eq_ref_candidate(TABLE_LIST *tl, table_map sj_inner_tables) { | |
| 6531 | 6645 | Key_use *keyuse = tl->table->reginfo.join_tab->keyuse(); | |
| 6532 | |||
| 6533 |
2/2✓ Branch 0 taken 5330 times.
✓ Branch 1 taken 1315 times.
|
6645 | if (keyuse) { |
| 6534 | while (true) /* For each key */ | ||
| 6535 | { | ||
| 6536 | 7080 | const uint key = keyuse->key; | |
| 6537 | 7080 | KEY *const keyinfo = tl->table->key_info + key; | |
| 6538 | 7080 | key_part_map bound_parts = 0; | |
| 6539 |
2/2✓ Branch 0 taken 6488 times.
✓ Branch 1 taken 592 times.
|
7080 | if ((keyinfo->flags & (HA_NOSAME)) == HA_NOSAME) { |
| 6540 | do /* For all equalities on all key parts */ | ||
| 6541 | { | ||
| 6542 | /* Check if this is "t.keypart = expr(outer_tables) */ | ||
| 6543 |
2/2✓ Branch 0 taken 2732 times.
✓ Branch 1 taken 5323 times.
|
8055 | if (!(keyuse->used_tables & sj_inner_tables) && |
| 6544 |
1/2✓ Branch 0 taken 2732 times.
✗ Branch 1 not taken.
|
2732 | !(keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL)) { |
| 6545 | /* | ||
| 6546 | Consider only if the resulting condition does not pass a NULL | ||
| 6547 | value through. Especially needed for a UNIQUE index on NULLable | ||
| 6548 | columns where a duplicate row is possible with NULL values. | ||
| 6549 | */ | ||
| 6550 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 2732 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2732 times.
✗ Branch 5 not taken.
|
2732 | if (keyuse->null_rejecting || !keyuse->val->is_nullable() || |
| 6551 | ✗ | !keyinfo->key_part[keyuse->keypart].field->is_nullable()) | |
| 6552 | 2732 | bound_parts |= (key_part_map)1 << keyuse->keypart; | |
| 6553 | } | ||
| 6554 | 8055 | keyuse++; | |
| 6555 |
4/4✓ Branch 0 taken 3617 times.
✓ Branch 1 taken 4438 times.
✓ Branch 2 taken 1567 times.
✓ Branch 3 taken 2050 times.
|
8055 | } while (keyuse->key == key && keyuse->table_ref == tl); |
| 6556 | |||
| 6557 |
2/2✓ Branch 0 taken 1796 times.
✓ Branch 1 taken 4692 times.
|
6488 | if (bound_parts == LOWER_BITS(uint, keyinfo->user_defined_key_parts)) |
| 6558 | 1796 | return true; | |
| 6559 |
2/2✓ Branch 0 taken 3021 times.
✓ Branch 1 taken 1671 times.
|
4692 | if (keyuse->table_ref != tl) return false; |
| 6560 | } else { | ||
| 6561 | do { | ||
| 6562 | 791 | keyuse++; | |
| 6563 |
2/2✓ Branch 0 taken 513 times.
✓ Branch 1 taken 278 times.
|
791 | if (keyuse->table_ref != tl) return false; |
| 6564 |
2/2✓ Branch 0 taken 199 times.
✓ Branch 1 taken 79 times.
|
278 | } while (keyuse->key == key); |
| 6565 | } | ||
| 6566 | 1750 | } | |
| 6567 | } | ||
| 6568 | 1315 | return false; | |
| 6569 | } | ||
| 6570 | |||
| 6571 | /** | ||
| 6572 | Pull tables out of semi-join nests based on functional dependencies | ||
| 6573 | |||
| 6574 | @param join The join where to do the semi-join table pullout | ||
| 6575 | |||
| 6576 | @return False if successful, true if error (Out of memory) | ||
| 6577 | |||
| 6578 | @details | ||
| 6579 | Pull tables out of semi-join nests based on functional dependencies, | ||
| 6580 | ie. if a table is accessed via eq_ref(outer_tables). | ||
| 6581 | The function may be called several times, the caller is responsible | ||
| 6582 | for setting up proper key information that this function acts upon. | ||
| 6583 | |||
| 6584 | PRECONDITIONS | ||
| 6585 | When this function is called, the join may have several semi-join nests | ||
| 6586 | but it is guaranteed that one semi-join nest does not contain another. | ||
| 6587 | For functionally dependent tables to be pulled out, key information must | ||
| 6588 | have been calculated (see update_ref_and_keys()). | ||
| 6589 | |||
| 6590 | POSTCONDITIONS | ||
| 6591 | * Tables that were pulled out are removed from the semi-join nest they | ||
| 6592 | belonged to and added to the parent join nest. | ||
| 6593 | * For these tables, the used_tables and not_null_tables fields of | ||
| 6594 | the semi-join nest they belonged to will be adjusted. | ||
| 6595 | The semi-join nest is also marked as correlated, and | ||
| 6596 | sj_corr_tables and sj_depends_on are adjusted if necessary. | ||
| 6597 | * Semi-join nests' sj_inner_tables is set equal to used_tables | ||
| 6598 | |||
| 6599 | NOTE | ||
| 6600 | Table pullout may make uncorrelated subquery correlated. Consider this | ||
| 6601 | example: | ||
| 6602 | |||
| 6603 | ... WHERE oe IN (SELECT it1.primary_key WHERE p(it1, it2) ... ) | ||
| 6604 | |||
| 6605 | here table it1 can be pulled out (we have it1.primary_key=oe which gives | ||
| 6606 | us functional dependency). Once it1 is pulled out, all references to it1 | ||
| 6607 | from p(it1, it2) become references to outside of the subquery and thus | ||
| 6608 | make the subquery (i.e. its semi-join nest) correlated. | ||
| 6609 | Making the subquery (i.e. its semi-join nest) correlated prevents us from | ||
| 6610 | using Materialization or LooseScan to execute it. | ||
| 6611 | */ | ||
| 6612 | |||
| 6613 | 4435 | static bool pull_out_semijoin_tables(JOIN *join) { | |
| 6614 |
1/2✓ Branch 0 taken 4435 times.
✗ Branch 1 not taken.
|
4435 | DBUG_TRACE; |
| 6615 | |||
| 6616 |
2/4✓ Branch 0 taken 4435 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4435 times.
|
4435 | assert(!join->query_block->sj_nests.empty()); |
| 6617 | |||
| 6618 | 4435 | Opt_trace_context *const trace = &join->thd->opt_trace; | |
| 6619 |
1/2✓ Branch 0 taken 4435 times.
✗ Branch 1 not taken.
|
4435 | Opt_trace_object trace_wrapper(trace); |
| 6620 |
1/2✓ Branch 0 taken 4435 times.
✗ Branch 1 not taken.
|
4435 | Opt_trace_array trace_pullout(trace, "pulled_out_semijoin_tables"); |
| 6621 | |||
| 6622 | /* Try pulling out tables from each semi-join nest */ | ||
| 6623 |
1/2✓ Branch 0 taken 4435 times.
✗ Branch 1 not taken.
|
4435 | for (auto sj_list_it = join->query_block->sj_nests.begin(); |
| 6624 |
4/6✓ Branch 0 taken 8980 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8980 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4545 times.
✓ Branch 5 taken 4435 times.
|
8980 | sj_list_it != join->query_block->sj_nests.end();) { |
| 6625 |
1/2✓ Branch 0 taken 4545 times.
✗ Branch 1 not taken.
|
4545 | TABLE_LIST *sj_nest = *sj_list_it; |
| 6626 |
2/2✓ Branch 0 taken 182 times.
✓ Branch 1 taken 4363 times.
|
4545 | if (sj_nest->is_aj_nest()) { |
| 6627 |
1/2✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
|
182 | ++sj_list_it; |
| 6628 | 182 | continue; | |
| 6629 | } | ||
| 6630 | 4363 | table_map pulled_tables = 0; | |
| 6631 | /* | ||
| 6632 | Calculate set of tables within this semi-join nest that have | ||
| 6633 | other dependent tables. They cannot be pulled out. For example, with | ||
| 6634 | t1 SEMIJOIN (t2 LEFT JOIN t3 ON ...) ON t1.a=t2.pk, | ||
| 6635 | t2 cannot be pulled out because t3 depends on it. | ||
| 6636 | */ | ||
| 6637 | 4363 | table_map dep_tables = 0; | |
| 6638 |
7/12✓ Branch 0 taken 4363 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4363 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11962 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11962 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 16325 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 11962 times.
✓ Branch 11 taken 4363 times.
|
16325 | for (TABLE_LIST *tbl : sj_nest->nested_join->join_list) { |
| 6639 |
2/2✓ Branch 0 taken 3786 times.
✓ Branch 1 taken 8176 times.
|
11962 | if (tbl->dep_tables & sj_nest->nested_join->used_tables) |
| 6640 | 3786 | dep_tables |= tbl->dep_tables; | |
| 6641 | } | ||
| 6642 | /* | ||
| 6643 | Find which tables we can pull out based on key dependency data. | ||
| 6644 | Note that pulling one table out can allow us to pull out some | ||
| 6645 | other tables too. | ||
| 6646 | */ | ||
| 6647 | bool pulled_a_table; | ||
| 6648 |
2/2✓ Branch 0 taken 1793 times.
✓ Branch 1 taken 4363 times.
|
6156 | do { |
| 6649 | 6156 | pulled_a_table = false; | |
| 6650 |
7/12✓ Branch 0 taken 6156 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6156 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13775 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13775 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 19931 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 13775 times.
✓ Branch 11 taken 6156 times.
|
19931 | for (TABLE_LIST *tbl : sj_nest->nested_join->join_list) { |
| 6651 |
6/6✓ Branch 0 taken 13774 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 11971 times.
✓ Branch 3 taken 1803 times.
✓ Branch 4 taken 6645 times.
✓ Branch 5 taken 7130 times.
|
25746 | if (tbl->table && !(pulled_tables & tbl->map()) && |
| 6652 |
2/2✓ Branch 0 taken 6645 times.
✓ Branch 1 taken 5326 times.
|
11971 | !(dep_tables & tbl->map())) { |
| 6653 |
2/2✓ Branch 0 taken 1796 times.
✓ Branch 1 taken 4849 times.
|
6645 | if (find_eq_ref_candidate( |
| 6654 | 6645 | tbl, sj_nest->nested_join->used_tables & ~pulled_tables)) { | |
| 6655 | 1796 | pulled_a_table = true; | |
| 6656 | 1796 | pulled_tables |= tbl->map(); | |
| 6657 |
3/6✓ Branch 0 taken 1796 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1796 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1796 times.
✗ Branch 5 not taken.
|
1796 | Opt_trace_object(trace).add_utf8_table(tbl).add( |
| 6658 | "functionally_dependent", true); | ||
| 6659 | /* | ||
| 6660 | Pulling a table out of uncorrelated subquery in general makes | ||
| 6661 | it correlated. See the NOTE to this function. | ||
| 6662 | */ | ||
| 6663 | 1796 | sj_nest->nested_join->sj_corr_tables |= tbl->map(); | |
| 6664 | 1796 | sj_nest->nested_join->sj_depends_on |= tbl->map(); | |
| 6665 | } | ||
| 6666 | } | ||
| 6667 | } | ||
| 6668 | } while (pulled_a_table); | ||
| 6669 | |||
| 6670 | /* | ||
| 6671 | Move the pulled out TABLE_LIST elements to the parents. | ||
| 6672 | */ | ||
| 6673 | 4363 | sj_nest->nested_join->used_tables &= ~pulled_tables; | |
| 6674 | 4363 | sj_nest->nested_join->not_null_tables &= ~pulled_tables; | |
| 6675 | |||
| 6676 | /* sj_inner_tables is a copy of nested_join->used_tables */ | ||
| 6677 | 4363 | sj_nest->sj_inner_tables = sj_nest->nested_join->used_tables; | |
| 6678 | |||
| 6679 | 4363 | bool remove = false; | |
| 6680 |
2/2✓ Branch 0 taken 1786 times.
✓ Branch 1 taken 2577 times.
|
4363 | if (pulled_tables) { |
| 6681 | 1786 | mem_root_deque<TABLE_LIST *> *upper_join_list = | |
| 6682 | 1786 | (sj_nest->embedding != nullptr) | |
| 6683 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1784 times.
|
1786 | ? &sj_nest->embedding->nested_join->join_list |
| 6684 | 1784 | : &join->query_block->top_join_list; | |
| 6685 | |||
| 6686 |
1/2✓ Branch 0 taken 1786 times.
✗ Branch 1 not taken.
|
1786 | Prepared_stmt_arena_holder ps_arena_holder(join->thd); |
| 6687 | |||
| 6688 |
1/2✓ Branch 0 taken 1786 times.
✗ Branch 1 not taken.
|
1786 | for (auto child_li = sj_nest->nested_join->join_list.begin(); |
| 6689 |
4/6✓ Branch 0 taken 3585 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3585 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1799 times.
✓ Branch 5 taken 1786 times.
|
3585 | child_li != sj_nest->nested_join->join_list.end();) { |
| 6690 |
1/2✓ Branch 0 taken 1799 times.
✗ Branch 1 not taken.
|
1799 | TABLE_LIST *tbl = *child_li; |
| 6691 |
5/6✓ Branch 0 taken 1799 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1796 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1796 times.
✓ Branch 5 taken 3 times.
|
1799 | if (tbl->table && !(sj_nest->nested_join->used_tables & tbl->map())) { |
| 6692 | /* | ||
| 6693 | Pull the table up in the same way as simplify_joins() does: | ||
| 6694 | update join_list and embedding pointers but keep next[_local] | ||
| 6695 | pointers. | ||
| 6696 | */ | ||
| 6697 |
1/2✓ Branch 0 taken 1796 times.
✗ Branch 1 not taken.
|
1796 | child_li = sj_nest->nested_join->join_list.erase(child_li); |
| 6698 | |||
| 6699 |
1/2✓ Branch 0 taken 1796 times.
✗ Branch 1 not taken.
|
1796 | upper_join_list->push_back(tbl); |
| 6700 | |||
| 6701 | 1796 | tbl->join_list = upper_join_list; | |
| 6702 | 1796 | tbl->embedding = sj_nest->embedding; | |
| 6703 | } else { | ||
| 6704 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | ++child_li; |
| 6705 | } | ||
| 6706 | } | ||
| 6707 | |||
| 6708 | /* Remove the sj-nest itself if we've removed everything from it */ | ||
| 6709 |
2/2✓ Branch 0 taken 1784 times.
✓ Branch 1 taken 2 times.
|
1786 | if (!sj_nest->nested_join->used_tables) { |
| 6710 |
4/8✓ Branch 0 taken 1784 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1784 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1784 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1784 times.
✗ Branch 7 not taken.
|
1784 | upper_join_list->erase(std::find(upper_join_list->begin(), |
| 6711 | upper_join_list->end(), sj_nest)); | ||
| 6712 | /* Also remove it from the list of SJ-nests: */ | ||
| 6713 | 1784 | remove = true; | |
| 6714 | } | ||
| 6715 | 1786 | } | |
| 6716 | |||
| 6717 |
2/2✓ Branch 0 taken 1784 times.
✓ Branch 1 taken 2579 times.
|
4363 | if (remove) { |
| 6718 |
1/2✓ Branch 0 taken 1784 times.
✗ Branch 1 not taken.
|
1784 | sj_list_it = join->query_block->sj_nests.erase(sj_list_it); |
| 6719 | } else { | ||
| 6720 |
1/2✓ Branch 0 taken 2579 times.
✗ Branch 1 not taken.
|
2579 | ++sj_list_it; |
| 6721 | } | ||
| 6722 | } | ||
| 6723 | 4435 | return false; | |
| 6724 | 4435 | } | |
| 6725 | |||
| 6726 | /* Values in optimize */ | ||
| 6727 | #define KEY_OPTIMIZE_EXISTS 1 | ||
| 6728 | #define KEY_OPTIMIZE_REF_OR_NULL 2 | ||
| 6729 | |||
| 6730 | /** | ||
| 6731 | Merge new key definitions to old ones, remove those not used in both. | ||
| 6732 | |||
| 6733 | This is called for OR between different levels. | ||
| 6734 | |||
| 6735 | To be able to do 'ref_or_null' we merge a comparison of a column | ||
| 6736 | and 'column IS NULL' to one test. This is useful for sub select queries | ||
| 6737 | that are internally transformed to something like:. | ||
| 6738 | |||
| 6739 | @code | ||
| 6740 | SELECT * FROM t1 WHERE t1.key=outer_ref_field or t1.key IS NULL | ||
| 6741 | @endcode | ||
| 6742 | |||
| 6743 | Key_field::null_rejecting is processed as follows: @n | ||
| 6744 | result has null_rejecting=true if it is set for both ORed references. | ||
| 6745 | for example: | ||
| 6746 | - (t2.key = t1.field OR t2.key = t1.field) -> null_rejecting=true | ||
| 6747 | - (t2.key = t1.field OR t2.key <=> t1.field) -> null_rejecting=false | ||
| 6748 | |||
| 6749 | @todo | ||
| 6750 | The result of this is that we're missing some 'ref' accesses. | ||
| 6751 | OptimizerTeam: Fix this | ||
| 6752 | */ | ||
| 6753 | |||
| 6754 | 30252 | static Key_field *merge_key_fields(Key_field *start, Key_field *new_fields, | |
| 6755 | Key_field *end, uint and_level) { | ||
| 6756 |
2/2✓ Branch 0 taken 27269 times.
✓ Branch 1 taken 2983 times.
|
30252 | if (start == new_fields) return start; // Impossible or |
| 6757 |
2/2✓ Branch 0 taken 282 times.
✓ Branch 1 taken 2701 times.
|
2983 | if (new_fields == end) return start; // No new fields, skip all |
| 6758 | |||
| 6759 | 2701 | Key_field *first_free = new_fields; | |
| 6760 | |||
| 6761 | /* Mark all found fields in old array */ | ||
| 6762 |
2/2✓ Branch 0 taken 3677 times.
✓ Branch 1 taken 2701 times.
|
6378 | for (; new_fields != end; new_fields++) { |
| 6763 | 3677 | const Field *const new_field = new_fields->item_field->field; | |
| 6764 | |||
| 6765 |
2/2✓ Branch 0 taken 32479 times.
✓ Branch 1 taken 2024 times.
|
34503 | for (Key_field *old = start; old != first_free; old++) { |
| 6766 | 32479 | const Field *const old_field = old->item_field->field; | |
| 6767 | |||
| 6768 | /* | ||
| 6769 | Check that the Field objects are the same, as we may have several | ||
| 6770 | Item_field objects pointing to the same Field: | ||
| 6771 | */ | ||
| 6772 |
2/2✓ Branch 0 taken 6157 times.
✓ Branch 1 taken 26322 times.
|
32479 | if (old_field == new_field) { |
| 6773 | /* | ||
| 6774 | NOTE: below const_item() call really works as "!used_tables()", i.e. | ||
| 6775 | it can return false where it is feasible to make it return true. | ||
| 6776 | |||
| 6777 | The cause is as follows: Some of the tables are already known to be | ||
| 6778 | const tables (the detection code is in JOIN::make_join_plan(), | ||
| 6779 | above the update_ref_and_keys() call), but we didn't propagate | ||
| 6780 | information about this: TABLE::const_table is not set to true, and | ||
| 6781 | Item::update_used_tables() hasn't been called for each item. | ||
| 6782 | The result of this is that we're missing some 'ref' accesses. | ||
| 6783 | TODO: OptimizerTeam: Fix this | ||
| 6784 | */ | ||
| 6785 |
2/2✓ Branch 0 taken 3692 times.
✓ Branch 1 taken 2465 times.
|
6157 | if (!new_fields->val->const_item()) { |
| 6786 | /* | ||
| 6787 | If the value matches, we can use the key reference. | ||
| 6788 | If not, we keep it until we have examined all new values | ||
| 6789 | */ | ||
| 6790 |
2/2✓ Branch 0 taken 534 times.
✓ Branch 1 taken 3158 times.
|
3692 | if (old->val->eq(new_fields->val, old_field->binary())) { |
| 6791 | 534 | old->level = and_level; | |
| 6792 | 534 | old->optimize = | |
| 6793 | 534 | ((old->optimize & new_fields->optimize & KEY_OPTIMIZE_EXISTS) | | |
| 6794 | 534 | ((old->optimize | new_fields->optimize) & | |
| 6795 | KEY_OPTIMIZE_REF_OR_NULL)); | ||
| 6796 | 534 | old->null_rejecting = | |
| 6797 |
2/4✓ Branch 0 taken 534 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 534 times.
✗ Branch 3 not taken.
|
534 | (old->null_rejecting && new_fields->null_rejecting); |
| 6798 | } | ||
| 6799 |
4/6✓ Branch 0 taken 2465 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2465 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 323 times.
✓ Branch 5 taken 2142 times.
|
4930 | } else if (old->eq_func && new_fields->eq_func && |
| 6800 |
2/2✓ Branch 0 taken 323 times.
✓ Branch 1 taken 2142 times.
|
2465 | old->val->eq_by_collation(new_fields->val, |
| 6801 | 2465 | old_field->binary(), | |
| 6802 | 2465 | old_field->charset())) { | |
| 6803 | 323 | old->level = and_level; | |
| 6804 | 323 | old->optimize = | |
| 6805 | 323 | ((old->optimize & new_fields->optimize & KEY_OPTIMIZE_EXISTS) | | |
| 6806 | 323 | ((old->optimize | new_fields->optimize) & | |
| 6807 | KEY_OPTIMIZE_REF_OR_NULL)); | ||
| 6808 | 323 | old->null_rejecting = | |
| 6809 |
3/4✓ Branch 0 taken 291 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 291 times.
✗ Branch 3 not taken.
|
323 | (old->null_rejecting && new_fields->null_rejecting); |
| 6810 |
4/6✓ Branch 0 taken 2142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 360 times.
✓ Branch 5 taken 1782 times.
|
4284 | } else if (old->eq_func && new_fields->eq_func && |
| 6811 |
4/4✓ Branch 0 taken 2024 times.
✓ Branch 1 taken 118 times.
✓ Branch 2 taken 1909 times.
✓ Branch 3 taken 115 times.
|
2142 | ((old->val->const_item() && old->val->is_null()) || |
| 6812 |
2/2✓ Branch 0 taken 245 times.
✓ Branch 1 taken 1782 times.
|
2027 | new_fields->val->is_null())) { |
| 6813 | /* field = expression OR field IS NULL */ | ||
| 6814 | 360 | old->level = and_level; | |
| 6815 | 360 | old->optimize = KEY_OPTIMIZE_REF_OR_NULL; | |
| 6816 | /* | ||
| 6817 | Remember the NOT NULL value unless the value does not depend | ||
| 6818 | on other tables. | ||
| 6819 | */ | ||
| 6820 |
6/6✓ Branch 0 taken 265 times.
✓ Branch 1 taken 95 times.
✓ Branch 2 taken 115 times.
✓ Branch 3 taken 150 times.
✓ Branch 4 taken 115 times.
✓ Branch 5 taken 245 times.
|
360 | if (!old->val->used_tables() && old->val->is_null()) |
| 6821 | 115 | old->val = new_fields->val; | |
| 6822 | /* The referred expression can be NULL: */ | ||
| 6823 | 360 | old->null_rejecting = false; | |
| 6824 | } else { | ||
| 6825 | /* | ||
| 6826 | We are comparing two different const. In this case we can't | ||
| 6827 | use a key-lookup on this so it's better to remove the value | ||
| 6828 | and let the range optimizer handle it | ||
| 6829 | */ | ||
| 6830 |
2/2✓ Branch 0 taken 1653 times.
✓ Branch 1 taken 129 times.
|
1782 | if (old == --first_free) // If last item |
| 6831 | 1653 | break; | |
| 6832 | 129 | *old = *first_free; // Remove old value | |
| 6833 | 129 | old--; // Retry this value | |
| 6834 | } | ||
| 6835 | } | ||
| 6836 | } | ||
| 6837 | } | ||
| 6838 | /* Remove all not used items */ | ||
| 6839 |
2/2✓ Branch 0 taken 1960 times.
✓ Branch 1 taken 2113 times.
|
4073 | for (Key_field *old = start; old != first_free;) { |
| 6840 |
2/2✓ Branch 0 taken 818 times.
✓ Branch 1 taken 1142 times.
|
1960 | if (old->level != and_level) { // Not used in all levels |
| 6841 |
2/2✓ Branch 0 taken 588 times.
✓ Branch 1 taken 230 times.
|
818 | if (old == --first_free) break; |
| 6842 | 230 | *old = *first_free; // Remove old value | |
| 6843 | 230 | continue; | |
| 6844 | } | ||
| 6845 | 1142 | old++; | |
| 6846 | } | ||
| 6847 | 2701 | return first_free; | |
| 6848 | } | ||
| 6849 | |||
| 6850 | /** | ||
| 6851 | Given a field, return its index in semi-join's select list, or UINT_MAX | ||
| 6852 | |||
| 6853 | @param item_field Field to be looked up in select list | ||
| 6854 | |||
| 6855 | @retval =UINT_MAX Field is not from a semijoin-transformed subquery | ||
| 6856 | @retval <UINT_MAX Index in select list of subquery | ||
| 6857 | |||
| 6858 | @details | ||
| 6859 | Given a field, find its table; then see if the table is within a | ||
| 6860 | semi-join nest and if the field was in select list of the subquery | ||
| 6861 | (if subquery was part of a quantified comparison predicate), or | ||
| 6862 | the field was a result of subquery decorrelation. | ||
| 6863 | If it was, then return the field's index in the select list. | ||
| 6864 | The value is used by LooseScan strategy. | ||
| 6865 | */ | ||
| 6866 | |||
| 6867 | 4837597 | static uint get_semi_join_select_list_index(Item_field *item_field) { | |
| 6868 | 4837597 | TABLE_LIST *emb_sj_nest = item_field->table_ref->embedding; | |
| 6869 |
6/6✓ Branch 0 taken 18721 times.
✓ Branch 1 taken 4818876 times.
✓ Branch 2 taken 16225 times.
✓ Branch 3 taken 2496 times.
✓ Branch 4 taken 16225 times.
✓ Branch 5 taken 4821372 times.
|
4837597 | if (emb_sj_nest && emb_sj_nest->is_sj_or_aj_nest()) { |
| 6870 | 16225 | const mem_root_deque<Item *> &items = | |
| 6871 | 16225 | emb_sj_nest->nested_join->sj_inner_exprs; | |
| 6872 |
2/2✓ Branch 0 taken 16303 times.
✓ Branch 1 taken 13889 times.
|
30192 | for (size_t i = 0; i < items.size(); i++) { |
| 6873 | 16303 | const Item *sel_item = items[i]; | |
| 6874 |
4/4✓ Branch 0 taken 3500 times.
✓ Branch 1 taken 12813 times.
✓ Branch 2 taken 2346 times.
✓ Branch 3 taken 13967 times.
|
19813 | if (sel_item->type() == Item::FIELD_ITEM && |
| 6875 |
2/2✓ Branch 0 taken 2346 times.
✓ Branch 1 taken 1154 times.
|
3500 | down_cast<const Item_field *>(sel_item)->field->eq(item_field->field)) |
| 6876 | 2346 | return i; | |
| 6877 | } | ||
| 6878 | } | ||
| 6879 | 4835261 | return UINT_MAX; | |
| 6880 | } | ||
| 6881 | |||
| 6882 | /** | ||
| 6883 | @brief | ||
| 6884 | If EXPLAIN or if the --safe-updates option is enabled, add a warning that an | ||
| 6885 | index cannot be used for ref access. | ||
| 6886 | |||
| 6887 | @details | ||
| 6888 | If EXPLAIN or if the --safe-updates option is enabled, add a warning for each | ||
| 6889 | index that cannot be used for ref access due to either type conversion or | ||
| 6890 | different collations on the field used for comparison | ||
| 6891 | |||
| 6892 | Example type conversion (char compared to int): | ||
| 6893 | |||
| 6894 | CREATE TABLE t1 (url char(1) PRIMARY KEY); | ||
| 6895 | SELECT * FROM t1 WHERE url=1; | ||
| 6896 | |||
| 6897 | Example different collations (danish vs german2): | ||
| 6898 | |||
| 6899 | CREATE TABLE t1 (url char(1) PRIMARY KEY) collate latin1_danish_ci; | ||
| 6900 | SELECT * FROM t1 WHERE url='1' collate latin1_german2_ci; | ||
| 6901 | |||
| 6902 | @param thd Thread for the connection that submitted the query | ||
| 6903 | @param field Field used in comparison | ||
| 6904 | @param cant_use_index Indexes that cannot be used for lookup | ||
| 6905 | */ | ||
| 6906 | 1336 | static void warn_index_not_applicable(THD *thd, const Field *field, | |
| 6907 | const Key_map cant_use_index) { | ||
| 6908 |
1/2✓ Branch 0 taken 1336 times.
✗ Branch 1 not taken.
|
1336 | Functional_index_error_handler functional_index_error_handler(field, thd); |
| 6909 | |||
| 6910 |
4/4✓ Branch 0 taken 1230 times.
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 109 times.
✓ Branch 3 taken 1227 times.
|
2566 | if (thd->lex->is_explain() || |
| 6911 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1227 times.
|
1230 | thd->variables.option_bits & OPTION_SAFE_UPDATES) |
| 6912 |
2/2✓ Branch 0 taken 192 times.
✓ Branch 1 taken 109 times.
|
301 | for (uint j = 0; j < field->table->s->keys; j++) |
| 6913 |
2/2✓ Branch 0 taken 98 times.
✓ Branch 1 taken 94 times.
|
192 | if (cant_use_index.is_set(j)) |
| 6914 |
1/2✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
|
98 | push_warning_printf(thd, Sql_condition::SL_WARNING, |
| 6915 | ER_WARN_INDEX_NOT_APPLICABLE, | ||
| 6916 | ER_THD(thd, ER_WARN_INDEX_NOT_APPLICABLE), "ref", | ||
| 6917 |
1/2✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
|
98 | field->table->key_info[j].name, field->field_name); |
| 6918 | 1336 | } | |
| 6919 | |||
| 6920 | /** | ||
| 6921 | Add a possible key to array of possible keys if it's usable as a key | ||
| 6922 | |||
| 6923 | @param [in,out] key_fields Used as an input parameter in the sense that it is | ||
| 6924 | a pointer to a pointer to a memory area where an array of Key_field objects | ||
| 6925 | will stored. It is used as an out parameter in the sense that the pointer will | ||
| 6926 | be updated to point beyond the last Key_field written. | ||
| 6927 | |||
| 6928 | @param thd session context | ||
| 6929 | @param and_level And level, to be stored in Key_field | ||
| 6930 | @param cond Condition predicate | ||
| 6931 | @param item_field Field used in comparison | ||
| 6932 | @param eq_func True if we used =, <=> or IS NULL | ||
| 6933 | @param value Array of values used for comparison with field | ||
| 6934 | @param num_values Number of elements in the array of values | ||
| 6935 | @param usable_tables Tables which can be used for key optimization | ||
| 6936 | @param sargables IN/OUT Array of found sargable candidates. | ||
| 6937 | Will be ignored in case eq_func is true. | ||
| 6938 | |||
| 6939 | @note | ||
| 6940 | If we are doing a NOT NULL comparison on a NOT NULL field in a outer join | ||
| 6941 | table, we store this to be able to do not exists optimization later. | ||
| 6942 | |||
| 6943 | |||
| 6944 | @returns false if success, true if error | ||
| 6945 | */ | ||
| 6946 | |||
| 6947 | 6942079 | static bool add_key_field(THD *thd, Key_field **key_fields, uint and_level, | |
| 6948 | Item_func *cond, Item_field *item_field, bool eq_func, | ||
| 6949 | Item **value, uint num_values, | ||
| 6950 | table_map usable_tables, SARGABLE_PARAM **sargables) { | ||
| 6951 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6942092 times.
|
6942079 | assert(cond->is_bool_func()); |
| 6952 |
3/4✓ Branch 0 taken 629675 times.
✓ Branch 1 taken 6312417 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 629675 times.
|
6942092 | assert(eq_func || sargables); |
| 6953 |
47/48✓ Branch 0 taken 6702831 times.
✓ Branch 1 taken 239261 times.
✓ Branch 2 taken 6449663 times.
✓ Branch 3 taken 253169 times.
✓ Branch 4 taken 6440159 times.
✓ Branch 5 taken 9504 times.
✓ Branch 6 taken 6428722 times.
✓ Branch 7 taken 11434 times.
✓ Branch 8 taken 6422047 times.
✓ Branch 9 taken 6676 times.
✓ Branch 10 taken 6416399 times.
✓ Branch 11 taken 5631 times.
✓ Branch 12 taken 355883 times.
✓ Branch 13 taken 6060514 times.
✓ Branch 14 taken 353285 times.
✓ Branch 15 taken 2598 times.
✓ Branch 16 taken 193007 times.
✓ Branch 17 taken 160278 times.
✓ Branch 18 taken 184480 times.
✓ Branch 19 taken 8527 times.
✓ Branch 20 taken 176321 times.
✓ Branch 21 taken 8159 times.
✓ Branch 22 taken 169955 times.
✓ Branch 23 taken 6366 times.
✓ Branch 24 taken 918 times.
✓ Branch 25 taken 169037 times.
✓ Branch 26 taken 477 times.
✓ Branch 27 taken 441 times.
✓ Branch 28 taken 428 times.
✓ Branch 29 taken 49 times.
✓ Branch 30 taken 302 times.
✓ Branch 31 taken 126 times.
✓ Branch 32 taken 225 times.
✓ Branch 33 taken 77 times.
✓ Branch 34 taken 164 times.
✓ Branch 35 taken 61 times.
✓ Branch 36 taken 127 times.
✓ Branch 37 taken 37 times.
✓ Branch 38 taken 119 times.
✓ Branch 39 taken 8 times.
✓ Branch 40 taken 109 times.
✓ Branch 41 taken 10 times.
✓ Branch 42 taken 62 times.
✓ Branch 43 taken 47 times.
✓ Branch 44 taken 22 times.
✓ Branch 45 taken 40 times.
✓ Branch 46 taken 32 times.
✗ Branch 47 not taken.
|
6942092 | assert(cond->functype() == Item_func::EQ_FUNC || |
| 6954 | cond->functype() == Item_func::NE_FUNC || | ||
| 6955 | cond->functype() == Item_func::GT_FUNC || | ||
| 6956 | cond->functype() == Item_func::LT_FUNC || | ||
| 6957 | cond->functype() == Item_func::GE_FUNC || | ||
| 6958 | cond->functype() == Item_func::LE_FUNC || | ||
| 6959 | cond->functype() == Item_func::MULT_EQUAL_FUNC || | ||
| 6960 | cond->functype() == Item_func::EQUAL_FUNC || | ||
| 6961 | cond->functype() == Item_func::LIKE_FUNC || | ||
| 6962 | cond->functype() == Item_func::ISNULL_FUNC || | ||
| 6963 | cond->functype() == Item_func::ISNOTNULL_FUNC || | ||
| 6964 | cond->functype() == Item_func::BETWEEN || | ||
| 6965 | cond->functype() == Item_func::IN_FUNC || | ||
| 6966 | cond->functype() == Item_func::MEMBER_OF_FUNC || | ||
| 6967 | cond->functype() == Item_func::SP_EQUALS_FUNC || | ||
| 6968 | cond->functype() == Item_func::SP_WITHIN_FUNC || | ||
| 6969 | cond->functype() == Item_func::SP_CONTAINS_FUNC || | ||
| 6970 | cond->functype() == Item_func::SP_INTERSECTS_FUNC || | ||
| 6971 | cond->functype() == Item_func::SP_DISJOINT_FUNC || | ||
| 6972 | cond->functype() == Item_func::SP_COVERS_FUNC || | ||
| 6973 | cond->functype() == Item_func::SP_COVEREDBY_FUNC || | ||
| 6974 | cond->functype() == Item_func::SP_OVERLAPS_FUNC || | ||
| 6975 | cond->functype() == Item_func::SP_TOUCHES_FUNC || | ||
| 6976 | cond->functype() == Item_func::SP_CROSSES_FUNC); | ||
| 6977 | |||
| 6978 | 6942040 | Field *const field = item_field->field; | |
| 6979 | 6942040 | TABLE_LIST *const tl = item_field->table_ref; | |
| 6980 | |||
| 6981 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6942037 times.
|
6942040 | if (tl->table->reginfo.join_tab == nullptr) { |
| 6982 | /* | ||
| 6983 | Due to a bug in IN-to-EXISTS (grep for real_item() in item_subselect.cc | ||
| 6984 | for more info), an index over a field from an outer query might be | ||
| 6985 | considered here, which is incorrect. Their query has been fully | ||
| 6986 | optimized already so their reginfo.join_tab is NULL and we reject them. | ||
| 6987 | */ | ||
| 6988 | 3 | return false; | |
| 6989 | } | ||
| 6990 | |||
| 6991 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6942073 times.
|
6942037 | DBUG_PRINT("info", ("add_key_field for field %s", field->field_name)); |
| 6992 | 6942078 | uint exists_optimize = 0; | |
| 6993 |
5/6✓ Branch 0 taken 6942080 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2955 times.
✓ Branch 3 taken 6939128 times.
✓ Branch 4 taken 1669 times.
✓ Branch 5 taken 6940412 times.
|
6945033 | if (!tl->derived_keys_ready && tl->uses_materialization() && |
| 6994 |
2/2✓ Branch 0 taken 1669 times.
✓ Branch 1 taken 1286 times.
|
2955 | !tl->table->is_created()) { |
| 6995 | bool allocated; | ||
| 6996 |
2/4✓ Branch 0 taken 1669 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1669 times.
|
1669 | if (tl->update_derived_keys(thd, field, value, num_values, &allocated)) |
| 6997 | 92 | return true; | |
| 6998 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 1577 times.
|
1669 | if (!allocated) return false; |
| 6999 | } | ||
| 7000 |
2/2✓ Branch 0 taken 1244632 times.
✓ Branch 1 taken 5697349 times.
|
6941989 | if (!field->is_flag_set(PART_KEY_FLAG)) { |
| 7001 | // Don't remove column IS NULL on a LEFT JOIN table | ||
| 7002 |
2/2✓ Branch 0 taken 3468 times.
✓ Branch 1 taken 952150 times.
|
955618 | if (!eq_func || (*value)->type() != Item::NULL_ITEM || |
| 7003 |
8/8✓ Branch 0 taken 955618 times.
✓ Branch 1 taken 289014 times.
✓ Branch 2 taken 808 times.
✓ Branch 3 taken 2660 times.
✓ Branch 4 taken 637 times.
✓ Branch 5 taken 168 times.
✓ Branch 6 taken 1244461 times.
✓ Branch 7 taken 168 times.
|
2200250 | !tl->table->is_nullable() || field->is_nullable()) |
| 7004 | 1244461 | return false; // Not a key. Skip it | |
| 7005 | 168 | exists_optimize = KEY_OPTIMIZE_EXISTS; | |
| 7006 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 168 times.
|
168 | assert(num_values == 1); |
| 7007 | } else { | ||
| 7008 | 5697349 | table_map used_tables = 0; | |
| 7009 | 5697349 | bool optimizable = false; | |
| 7010 |
2/2✓ Branch 0 taken 5941599 times.
✓ Branch 1 taken 5697362 times.
|
11638961 | for (uint i = 0; i < num_values; i++) { |
| 7011 | 5941599 | used_tables |= (value[i])->used_tables(); | |
| 7012 |
2/2✓ Branch 0 taken 5939309 times.
✓ Branch 1 taken 2303 times.
|
5941605 | if (!((value[i])->used_tables() & (tl->map() | RAND_TABLE_BIT))) |
| 7013 | 5939309 | optimizable = true; | |
| 7014 | } | ||
| 7015 |
2/2✓ Branch 0 taken 2229 times.
✓ Branch 1 taken 5695133 times.
|
5697362 | if (!optimizable) return false; |
| 7016 |
2/2✓ Branch 0 taken 518071 times.
✓ Branch 1 taken 5177012 times.
|
5695133 | if (!(usable_tables & tl->map())) { |
| 7017 |
2/2✓ Branch 0 taken 2264 times.
✓ Branch 1 taken 514361 times.
|
516624 | if (!eq_func || (*value)->type() != Item::NULL_ITEM || |
| 7018 |
8/8✓ Branch 0 taken 516624 times.
✓ Branch 1 taken 1447 times.
✓ Branch 2 taken 2248 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 2140 times.
✓ Branch 5 taken 112 times.
✓ Branch 6 taken 517964 times.
✓ Branch 7 taken 112 times.
|
1034696 | !tl->table->is_nullable() || field->is_nullable()) |
| 7019 | 517964 | return false; // Can't use left join optimize | |
| 7020 | 112 | exists_optimize = KEY_OPTIMIZE_EXISTS; | |
| 7021 | } else { | ||
| 7022 | 5177012 | JOIN_TAB *stat = tl->table->reginfo.join_tab; | |
| 7023 | 5177012 | Key_map possible_keys = field->key_start; | |
| 7024 | 5177012 | possible_keys.intersect(tl->table->keys_in_use_for_query); | |
| 7025 | 5177054 | stat[0].keys().merge(possible_keys); // Add possible keys | |
| 7026 | |||
| 7027 | /* | ||
| 7028 | Save the following cases: | ||
| 7029 | Field op constant | ||
| 7030 | Field LIKE constant where constant doesn't start with a wildcard | ||
| 7031 | Field = field2 where field2 is in a different table | ||
| 7032 | Field op formula | ||
| 7033 | Field IS NULL | ||
| 7034 | Field IS NOT NULL | ||
| 7035 | Field BETWEEN ... | ||
| 7036 | Field IN ... | ||
| 7037 | */ | ||
| 7038 | 5177062 | stat[0].key_dependent |= used_tables; | |
| 7039 | |||
| 7040 | 5177062 | bool is_const = true; | |
| 7041 |
2/2✓ Branch 0 taken 5421112 times.
✓ Branch 1 taken 1322929 times.
|
6744041 | for (uint i = 0; i < num_values; i++) { |
| 7042 |
3/4✓ Branch 0 taken 5421117 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3854138 times.
✓ Branch 3 taken 1566979 times.
|
5421112 | if (!(is_const &= value[i]->const_for_execution())) break; |
| 7043 | } | ||
| 7044 |
2/2✓ Branch 0 taken 1322929 times.
✓ Branch 1 taken 3854138 times.
|
5177067 | if (is_const) |
| 7045 | 1322929 | stat[0].const_keys.merge(possible_keys); | |
| 7046 |
2/2✓ Branch 0 taken 1130 times.
✓ Branch 1 taken 3853008 times.
|
3854138 | else if (!eq_func) { |
| 7047 | /* | ||
| 7048 | Save info to be able check whether this predicate can be | ||
| 7049 | considered as sargable for range analysis after reading const tables. | ||
| 7050 | We do not save info about equalities as update_const_equal_items | ||
| 7051 | will take care of updating info on keys from sargable equalities. | ||
| 7052 | */ | ||
| 7053 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1130 times.
|
1130 | assert(sargables); |
| 7054 | 1130 | (*sargables)--; | |
| 7055 | /* | ||
| 7056 | The sargables and key_fields arrays share the same memory | ||
| 7057 | buffer, and grow from opposite directions, so make sure they | ||
| 7058 | don't cross. | ||
| 7059 | */ | ||
| 7060 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1130 times.
|
1130 | assert(*sargables > reinterpret_cast<SARGABLE_PARAM *>(*key_fields)); |
| 7061 | 1130 | (*sargables)->field = field; | |
| 7062 | 1130 | (*sargables)->arg_value = value; | |
| 7063 | 1130 | (*sargables)->num_values = num_values; | |
| 7064 | } | ||
| 7065 | /* | ||
| 7066 | We can't always use indexes when comparing a string index to a | ||
| 7067 | number. cmp_type() is checked to allow compare of dates to numbers. | ||
| 7068 | eq_func is NEVER true when num_values > 1 | ||
| 7069 | */ | ||
| 7070 |
2/2✓ Branch 0 taken 338390 times.
✓ Branch 1 taken 4838667 times.
|
5178393 | if (!eq_func) return false; |
| 7071 | |||
| 7072 | /* | ||
| 7073 | Check if the field and value are comparable in the index. | ||
| 7074 | */ | ||
| 7075 |
2/4✓ Branch 0 taken 4838671 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4838674 times.
✗ Branch 3 not taken.
|
4838667 | if (!comparable_in_index(cond, field, Field::itRAW, cond->functype(), |
| 7076 |
4/4✓ Branch 0 taken 4837562 times.
✓ Branch 1 taken 1112 times.
✓ Branch 2 taken 1336 times.
✓ Branch 3 taken 4837334 times.
|
9676232 | *value) || |
| 7077 |
3/4✓ Branch 0 taken 4837554 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 661632 times.
✓ Branch 3 taken 4175922 times.
|
4837562 | (field->cmp_type() == STRING_RESULT && |
| 7078 |
3/4✓ Branch 0 taken 661629 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 661277 times.
✓ Branch 3 taken 352 times.
|
661632 | field->match_collation_to_optimize_range() && |
| 7079 |
4/6✓ Branch 0 taken 661279 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 661284 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 224 times.
✓ Branch 5 taken 661060 times.
|
661277 | field->charset() != cond->compare_collation())) { |
| 7080 |
1/2✓ Branch 0 taken 1336 times.
✗ Branch 1 not taken.
|
1336 | warn_index_not_applicable(stat->join()->thd, field, possible_keys); |
| 7081 | 1336 | return false; | |
| 7082 | } | ||
| 7083 | } | ||
| 7084 | } | ||
| 7085 | /* | ||
| 7086 | For the moment eq_func is always true. This slot is reserved for future | ||
| 7087 | extensions where we want to remembers other things than just eq comparisons | ||
| 7088 | */ | ||
| 7089 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4837614 times.
|
4837614 | assert(eq_func); |
| 7090 | /* | ||
| 7091 | Calculate the "null rejecting" property based on the type of predicate. | ||
| 7092 | Only the <=> operator and the IS NULL and IS NOT NULL clauses may return | ||
| 7093 | true on nullable operands that have the NULL value - assuming that all | ||
| 7094 | other predicates are augmented with IS TRUE or IS FALSE truth clause, | ||
| 7095 | so that all UNKNOWN results are converted to TRUE or FALSE. | ||
| 7096 | |||
| 7097 | The "null rejecting" property can be combined with the left and right | ||
| 7098 | operands to perform certain optimizations. | ||
| 7099 | |||
| 7100 | If the condition has form "left.field = right.keypart" and left.field can | ||
| 7101 | be NULL, there will be no matches if left.field is NULL. | ||
| 7102 | We use null_rejecting in add_not_null_conds() to add | ||
| 7103 | 'left.field IS NOT NULL' to tab->m_condition, if this is not an outer | ||
| 7104 | join. We also use it to shortcut reading rows from table "right" when | ||
| 7105 | left.field is found to be a NULL value (in RefIterator and BKA). | ||
| 7106 | |||
| 7107 | It is also possible to apply optimizations to the indexed table. | ||
| 7108 | If the operation is null rejecting and there is a unique index over | ||
| 7109 | the key field, an eq_ref operation can be performed on the index, since | ||
| 7110 | we have no interest in the NULL values. | ||
| 7111 | |||
| 7112 | Notice however that the null rejecting property may be cancelled out | ||
| 7113 | by the KEY_OPTIMIZE_REF_OR_NULL property: this can be set when having: | ||
| 7114 | |||
| 7115 | left.field = right.keypart OR right.keypart IS NULL. | ||
| 7116 | */ | ||
| 7117 | 4837614 | const bool null_rejecting = cond->functype() != Item_func::EQUAL_FUNC && | |
| 7118 |
4/4✓ Branch 0 taken 4836328 times.
✓ Branch 1 taken 1289 times.
✓ Branch 2 taken 4833171 times.
✓ Branch 3 taken 3154 times.
|
9670780 | cond->functype() != Item_func::ISNULL_FUNC && |
| 7119 |
1/2✓ Branch 0 taken 4833183 times.
✗ Branch 1 not taken.
|
4833171 | cond->functype() != Item_func::ISNOTNULL_FUNC; |
| 7120 | |||
| 7121 | /* Store possible eq field */ | ||
| 7122 | 4837607 | new (*key_fields) Key_field(item_field, *value, and_level, exists_optimize, | |
| 7123 | eq_func, null_rejecting, nullptr, | ||
| 7124 | 4837606 | get_semi_join_select_list_index(item_field)); | |
| 7125 | 4837609 | (*key_fields)++; | |
| 7126 | /* | ||
| 7127 | The sargables and key_fields arrays share the same memory buffer, | ||
| 7128 | and grow from opposite directions, so make sure they don't | ||
| 7129 | cross. But if sargables was NULL, eq_func had to be true and we | ||
| 7130 | don't write any sargables. | ||
| 7131 | */ | ||
| 7132 |
3/4✓ Branch 0 taken 4836938 times.
✓ Branch 1 taken 671 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4836938 times.
|
4837609 | assert(sargables == nullptr || |
| 7133 | *key_fields < reinterpret_cast<Key_field *>(*sargables)); | ||
| 7134 | |||
| 7135 | 4837609 | return false; | |
| 7136 | } | ||
| 7137 | |||
| 7138 | /** | ||
| 7139 | Add possible keys to array of possible keys originated from a simple | ||
| 7140 | predicate. | ||
| 7141 | |||
| 7142 | @param thd session context | ||
| 7143 | @param[in,out] key_fields Pointer to add key, if usable | ||
| 7144 | is incremented if key was stored in the array | ||
| 7145 | @param and_level And level, to be stored in Key_field | ||
| 7146 | @param cond Condition predicate | ||
| 7147 | @param field_item Field used in comparison | ||
| 7148 | @param eq_func True if we used =, <=> or IS NULL | ||
| 7149 | @param val Value used for comparison with field | ||
| 7150 | Is NULL for BETWEEN and IN | ||
| 7151 | @param num_values Number of elements in the array of values | ||
| 7152 | @param usable_tables Tables which can be used for key optimization | ||
| 7153 | @param sargables IN/OUT Array of found sargable candidates | ||
| 7154 | |||
| 7155 | @note | ||
| 7156 | If field items f1 and f2 belong to the same multiple equality and | ||
| 7157 | a key is added for f1, the the same key is added for f2. | ||
| 7158 | |||
| 7159 | @returns false if success, true if error | ||
| 7160 | */ | ||
| 7161 | |||
| 7162 | 877895 | static bool add_key_equal_fields(THD *thd, Key_field **key_fields, | |
| 7163 | uint and_level, Item_func *cond, | ||
| 7164 | Item_field *field_item, bool eq_func, | ||
| 7165 | Item **val, uint num_values, | ||
| 7166 | table_map usable_tables, | ||
| 7167 | SARGABLE_PARAM **sargables) { | ||
| 7168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 877896 times.
|
877895 | assert(cond->is_bool_func()); |
| 7169 | |||
| 7170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 877895 times.
|
877896 | if (add_key_field(thd, key_fields, and_level, cond, field_item, eq_func, val, |
| 7171 | num_values, usable_tables, sargables)) | ||
| 7172 | ✗ | return true; | |
| 7173 | 877895 | Item_equal *item_equal = field_item->item_equal; | |
| 7174 |
2/2✓ Branch 0 taken 875147 times.
✓ Branch 1 taken 2748 times.
|
877895 | if (item_equal == nullptr) return false; |
| 7175 | /* | ||
| 7176 | Add to the set of possible key values every substitution of | ||
| 7177 | the field for an equal field included into item_equal | ||
| 7178 | */ | ||
| 7179 |
5/8✓ Branch 0 taken 2749 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2749 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8210 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5461 times.
✓ Branch 7 taken 2749 times.
|
8210 | for (Item_field &item : item_equal->get_fields()) { |
| 7180 |
3/4✓ Branch 0 taken 5461 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2712 times.
✓ Branch 3 taken 2749 times.
|
5461 | if (!field_item->field->eq(item.field)) { |
| 7181 |
2/4✓ Branch 0 taken 2712 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2712 times.
|
2712 | if (add_key_field(thd, key_fields, and_level, cond, &item, eq_func, val, |
| 7182 | num_values, usable_tables, sargables)) | ||
| 7183 | ✗ | return true; | |
| 7184 | } | ||
| 7185 | } | ||
| 7186 | 2749 | return false; | |
| 7187 | } | ||
| 7188 | |||
| 7189 | /** | ||
| 7190 | Check if an expression is a non-outer field. | ||
| 7191 | |||
| 7192 | Checks if an expression is a field and belongs to the current select. | ||
| 7193 | |||
| 7194 | @param field Item expression to check | ||
| 7195 | |||
| 7196 | @return boolean | ||
| 7197 | @retval true the expression is a local field | ||
| 7198 | @retval false it's something else | ||
| 7199 | */ | ||
| 7200 | |||
| 7201 | 2238982 | static bool is_local_field(Item *field) { | |
| 7202 | 2238982 | return field->real_item()->type() == Item::FIELD_ITEM && | |
| 7203 |
2/2✓ Branch 0 taken 875501 times.
✓ Branch 1 taken 2023 times.
|
877524 | !field->is_outer_reference() && |
| 7204 |
4/4✓ Branch 0 taken 877524 times.
✓ Branch 1 taken 1361470 times.
✓ Branch 2 taken 875494 times.
✓ Branch 3 taken 7 times.
|
3992015 | !down_cast<Item_ident *>(field)->depended_from && |
| 7205 |
2/2✓ Branch 0 taken 875494 times.
✓ Branch 1 taken 3 times.
|
3114491 | !down_cast<Item_ident *>(field->real_item())->depended_from; |
| 7206 | } | ||
| 7207 | |||
| 7208 | /** | ||
| 7209 | Check if a row constructor expression is over columns in the same query block. | ||
| 7210 | |||
| 7211 | @param item_row Row expression to check. | ||
| 7212 | |||
| 7213 | @return boolean | ||
| 7214 | @retval true The expression is a local column reference. | ||
| 7215 | @retval false It's something else. | ||
| 7216 | */ | ||
| 7217 | 229 | static bool is_row_of_local_columns(Item_row *item_row) { | |
| 7218 |
2/2✓ Branch 0 taken 488 times.
✓ Branch 1 taken 205 times.
|
693 | for (uint i = 0; i < item_row->cols(); ++i) |
| 7219 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 464 times.
|
488 | if (!is_local_field(item_row->element_index(i))) return false; |
| 7220 | 205 | return true; | |
| 7221 | } | ||
| 7222 | |||
| 7223 | /** | ||
| 7224 | The guts of the ref optimizer. This function, along with the other | ||
| 7225 | add_key_* functions, make up a recursive procedure that analyzes a | ||
| 7226 | condition expression (a tree of AND and OR predicates) and does | ||
| 7227 | many things. | ||
| 7228 | |||
| 7229 | @param thd session context | ||
| 7230 | @param join The query block involving the condition. | ||
| 7231 | @param [in,out] key_fields Start of memory buffer, see below. | ||
| 7232 | @param [in,out] and_level Current 'and level', see below. | ||
| 7233 | @param cond The conditional expression to analyze. | ||
| 7234 | @param usable_tables Tables not in this bitmap will not be examined. | ||
| 7235 | @param [in,out] sargables End of memory buffer, see below. | ||
| 7236 | |||
| 7237 | @returns false if success, true if error | ||
| 7238 | |||
| 7239 | This documentation is the result of reverse engineering and may | ||
| 7240 | therefore not capture the full gist of the procedure, but it is | ||
| 7241 | known to do the following: | ||
| 7242 | |||
| 7243 | - Populate a raw memory buffer from two directions at the same time. An | ||
| 7244 | 'array' of Key_field objects fill the buffer from low to high addresses | ||
| 7245 | whilst an 'array' of SARGABLE_PARAM's fills the buffer from high to low | ||
| 7246 | addresses. At the first call to this function, it is assumed that | ||
| 7247 | key_fields points to the beginning of the buffer and sargables point to the | ||
| 7248 | end (except for a poor-mans 'null element' at the very end). | ||
| 7249 | |||
| 7250 | - Update a number of properties in the JOIN_TAB's that can be used | ||
| 7251 | to find search keys (sargables). | ||
| 7252 | |||
| 7253 | - JOIN_TAB::keys | ||
| 7254 | - JOIN_TAB::key_dependent | ||
| 7255 | - JOIN_TAB::const_keys (dictates if the range optimizer will be run | ||
| 7256 | later.) | ||
| 7257 | |||
| 7258 | The Key_field objects are marked with something called an 'and_level', which | ||
| 7259 | does @b not correspond to their nesting depth within the expression tree. It | ||
| 7260 | is rather a tag to group conjunctions together. For instance, in the | ||
| 7261 | conditional expression | ||
| 7262 | |||
| 7263 | @code | ||
| 7264 | a = 0 AND b = 0 | ||
| 7265 | @endcode | ||
| 7266 | |||
| 7267 | two Key_field's are produced, both having an and_level of 0. | ||
| 7268 | |||
| 7269 | In an expression such as | ||
| 7270 | |||
| 7271 | @code | ||
| 7272 | a = 0 AND b = 0 OR a = 1 | ||
| 7273 | @endcode | ||
| 7274 | |||
| 7275 | three Key_field's are produced, the first two corresponding to 'a = 0' and | ||
| 7276 | 'b = 0', respectively, both with and_level 0. The third one corresponds to | ||
| 7277 | 'a = 1' and has an and_level of 1. | ||
| 7278 | |||
| 7279 | A separate function, merge_key_fields() performs ref access validation on | ||
| 7280 | the Key_field array on the recursice ascent. If some Key_field's cannot be | ||
| 7281 | used for ref access, the key_fields pointer is rolled back. All other | ||
| 7282 | modifications to the query plan remain. | ||
| 7283 | */ | ||
| 7284 | 5907127 | bool add_key_fields(THD *thd, JOIN *join, Key_field **key_fields, | |
| 7285 | uint *and_level, Item *cond, table_map usable_tables, | ||
| 7286 | SARGABLE_PARAM **sargables) { | ||
| 7287 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5907140 times.
|
5907127 | assert(cond->is_bool_func()); |
| 7288 | |||
| 7289 |
2/2✓ Branch 0 taken 975354 times.
✓ Branch 1 taken 4931785 times.
|
5907140 | if (cond->type() == Item_func::COND_ITEM) { |
| 7290 |
1/2✓ Branch 0 taken 975360 times.
✗ Branch 1 not taken.
|
975354 | List_iterator_fast<Item> li(*((Item_cond *)cond)->argument_list()); |
| 7291 | 975360 | Key_field *org_key_fields = *key_fields; | |
| 7292 | |||
| 7293 |
3/4✓ Branch 0 taken 975354 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 955269 times.
✓ Branch 3 taken 20085 times.
|
975360 | if (down_cast<Item_cond *>(cond)->functype() == Item_func::COND_AND_FUNC) { |
| 7294 | Item *item; | ||
| 7295 |
2/2✓ Branch 0 taken 4147362 times.
✓ Branch 1 taken 955273 times.
|
5102634 | while ((item = li++)) { |
| 7296 |
2/4✓ Branch 0 taken 4147365 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4147365 times.
|
4147362 | if (add_key_fields(thd, join, key_fields, and_level, item, |
| 7297 | usable_tables, sargables)) | ||
| 7298 | ✗ | return true; | |
| 7299 | } | ||
| 7300 |
2/2✓ Branch 0 taken 3992919 times.
✓ Branch 1 taken 955273 times.
|
4948192 | for (; org_key_fields != *key_fields; org_key_fields++) |
| 7301 | 3992919 | org_key_fields->level = *and_level; | |
| 7302 | } else { | ||
| 7303 | 20085 | (*and_level)++; | |
| 7304 |
2/4✓ Branch 0 taken 20085 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20085 times.
|
20085 | if (add_key_fields(thd, join, key_fields, and_level, li++, usable_tables, |
| 7305 | sargables)) | ||
| 7306 | ✗ | return true; | |
| 7307 | Item *item; | ||
| 7308 |
2/2✓ Branch 0 taken 30250 times.
✓ Branch 1 taken 20087 times.
|
50337 | while ((item = li++)) { |
| 7309 | 30250 | Key_field *start_key_fields = *key_fields; | |
| 7310 | 30250 | (*and_level)++; | |
| 7311 |
2/4✓ Branch 0 taken 30252 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30252 times.
|
30250 | if (add_key_fields(thd, join, key_fields, and_level, item, |
| 7312 | usable_tables, sargables)) | ||
| 7313 | ✗ | return true; | |
| 7314 | 30252 | *key_fields = merge_key_fields(org_key_fields, start_key_fields, | |
| 7315 |
1/2✓ Branch 0 taken 30252 times.
✗ Branch 1 not taken.
|
30252 | *key_fields, ++(*and_level)); |
| 7316 | } | ||
| 7317 | } | ||
| 7318 | 975360 | return false; | |
| 7319 | } | ||
| 7320 | |||
| 7321 | /* | ||
| 7322 | Subquery optimization: Conditions that are pushed down into subqueries | ||
| 7323 | are wrapped into Item_func_trig_cond. We process the wrapped condition | ||
| 7324 | but need to set cond_guard for Key_use elements generated from it. | ||
| 7325 | */ | ||
| 7326 |
4/4✓ Branch 0 taken 4931745 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 486 times.
✓ Branch 3 taken 4931297 times.
|
9863544 | if (cond->type() == Item::FUNC_ITEM && |
| 7327 |
2/2✓ Branch 0 taken 486 times.
✓ Branch 1 taken 4931273 times.
|
4931745 | down_cast<Item_func *>(cond)->functype() == Item_func::TRIG_COND_FUNC) { |
| 7328 | 486 | Item *const cond_arg = down_cast<Item_func *>(cond)->arguments()[0]; | |
| 7329 |
1/2✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
|
972 | if (join->group_list.empty() && join->order.empty() && |
| 7330 |
1/2✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
|
486 | join->query_expression()->item && |
| 7331 |
5/6✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 418 times.
✓ Branch 3 taken 68 times.
✓ Branch 4 taken 417 times.
✓ Branch 5 taken 69 times.
|
1390 | join->query_expression()->item->substype() == Item_subselect::IN_SUBS && |
| 7332 |
2/2✓ Branch 0 taken 417 times.
✓ Branch 1 taken 1 times.
|
418 | !join->query_expression()->is_union()) { |
| 7333 | 417 | Key_field *save = *key_fields; | |
| 7334 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 417 times.
|
417 | if (add_key_fields(thd, join, key_fields, and_level, cond_arg, |
| 7335 | usable_tables, sargables)) | ||
| 7336 | ✗ | return true; | |
| 7337 | // Indicate that this ref access candidate is for subquery lookup: | ||
| 7338 |
2/2✓ Branch 0 taken 81 times.
✓ Branch 1 taken 417 times.
|
498 | for (; save != *key_fields; save++) |
| 7339 | 81 | save->cond_guard = ((Item_func_trig_cond *)cond)->get_trig_var(); | |
| 7340 | } | ||
| 7341 | 486 | return false; | |
| 7342 | } | ||
| 7343 | |||
| 7344 | /* If item is of type 'field op field/constant' add it to key_fields */ | ||
| 7345 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 4931245 times.
|
4931297 | if (cond->type() != Item::FUNC_ITEM) return false; |
| 7346 | 4931245 | Item_func *const cond_func = down_cast<Item_func *>(cond); | |
| 7347 | 4931263 | auto optimize = cond_func->select_optimize(thd); | |
| 7348 | // Catch errors that might be thrown during select_optimize() | ||
| 7349 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4931232 times.
|
4931260 | if (thd->is_error()) return true; |
| 7350 |
5/6✓ Branch 0 taken 235980 times.
✓ Branch 1 taken 1127192 times.
✓ Branch 2 taken 413648 times.
✓ Branch 3 taken 17266 times.
✓ Branch 4 taken 3137157 times.
✗ Branch 5 not taken.
|
4931232 | switch (optimize) { |
| 7351 | 235980 | case Item_func::OPTIMIZE_NONE: | |
| 7352 | 4931240 | break; | |
| 7353 | 1127192 | case Item_func::OPTIMIZE_KEY: { | |
| 7354 | Item **values; | ||
| 7355 | /* | ||
| 7356 | Build list of possible keys for 'a BETWEEN low AND high'. | ||
| 7357 | It is handled similar to the equivalent condition | ||
| 7358 | 'a >= low AND a <= high': | ||
| 7359 | */ | ||
| 7360 |
3/4✓ Branch 0 taken 1127201 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7091 times.
✓ Branch 3 taken 1120110 times.
|
1127192 | if (cond_func->functype() == Item_func::BETWEEN) { |
| 7361 | Item_field *field_item; | ||
| 7362 | 7091 | bool equal_func = false; | |
| 7363 | 7091 | uint num_values = 2; | |
| 7364 |
1/2✓ Branch 0 taken 7091 times.
✗ Branch 1 not taken.
|
7091 | values = cond_func->arguments(); |
| 7365 | |||
| 7366 | bool binary_cmp = | ||
| 7367 |
2/4✓ Branch 0 taken 7091 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7091 times.
✗ Branch 3 not taken.
|
7091 | (values[0]->real_item()->type() == Item::FIELD_ITEM) |
| 7368 |
6/8✓ Branch 0 taken 5854 times.
✓ Branch 1 taken 1237 times.
✓ Branch 2 taken 5854 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5854 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5641 times.
✓ Branch 7 taken 213 times.
|
7091 | ? ((Item_field *)values[0]->real_item())->field->binary() |
| 7369 | 7091 | : true; | |
| 7370 | |||
| 7371 | /* | ||
| 7372 | Additional optimization: If 'low = high': | ||
| 7373 | Handle as if the condition was "t.key = low". | ||
| 7374 | */ | ||
| 7375 |
4/4✓ Branch 0 taken 6929 times.
✓ Branch 1 taken 162 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 7016 times.
|
14020 | if (!((Item_func_between *)cond_func)->negated && |
| 7376 |
3/4✓ Branch 0 taken 6929 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 6854 times.
|
6929 | values[1]->eq(values[2], binary_cmp)) { |
| 7377 | 75 | equal_func = true; | |
| 7378 | 75 | num_values = 1; | |
| 7379 | } | ||
| 7380 | |||
| 7381 | /* | ||
| 7382 | Append keys for 'field <cmp> value[]' if the | ||
| 7383 | condition is of the form:: | ||
| 7384 | '<field> BETWEEN value[1] AND value[2]' | ||
| 7385 | */ | ||
| 7386 |
3/4✓ Branch 0 taken 7091 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5854 times.
✓ Branch 3 taken 1237 times.
|
7091 | if (is_local_field(values[0])) { |
| 7387 |
1/2✓ Branch 0 taken 5854 times.
✗ Branch 1 not taken.
|
5854 | field_item = (Item_field *)(values[0]->real_item()); |
| 7388 |
2/4✓ Branch 0 taken 5854 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5854 times.
|
5854 | if (add_key_equal_fields(thd, key_fields, *and_level, cond_func, |
| 7389 | field_item, equal_func, &values[1], | ||
| 7390 | num_values, usable_tables, sargables)) | ||
| 7391 | ✗ | return true; | |
| 7392 | } | ||
| 7393 | /* | ||
| 7394 | Append keys for 'value[0] <cmp> field' if the | ||
| 7395 | condition is of the form: | ||
| 7396 | 'value[0] BETWEEN field1 AND field2' | ||
| 7397 | */ | ||
| 7398 |
2/2✓ Branch 0 taken 14107 times.
✓ Branch 1 taken 7091 times.
|
21198 | for (uint i = 1; i <= num_values; i++) { |
| 7399 |
3/4✓ Branch 0 taken 14107 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 394 times.
✓ Branch 3 taken 13713 times.
|
14107 | if (is_local_field(values[i])) { |
| 7400 |
1/2✓ Branch 0 taken 394 times.
✗ Branch 1 not taken.
|
394 | field_item = (Item_field *)(values[i]->real_item()); |
| 7401 |
2/4✓ Branch 0 taken 394 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 394 times.
|
394 | if (add_key_equal_fields(thd, key_fields, *and_level, cond_func, |
| 7402 | field_item, equal_func, values, 1, | ||
| 7403 | usable_tables, sargables)) | ||
| 7404 | ✗ | return true; | |
| 7405 | } | ||
| 7406 | } | ||
| 7407 | } // if ( ... Item_func::BETWEEN) | ||
| 7408 |
5/6✓ Branch 0 taken 1120100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 462 times.
✓ Branch 3 taken 1119638 times.
✓ Branch 4 taken 441 times.
✓ Branch 5 taken 1119659 times.
|
1120572 | else if (cond_func->functype() == Item_func::MEMBER_OF_FUNC && |
| 7409 |
4/6✓ Branch 0 taken 462 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 462 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 441 times.
✓ Branch 5 taken 21 times.
|
462 | is_local_field(cond_func->key_item())) { |
| 7410 | // The predicate is <val> IN (<typed array>) | ||
| 7411 |
1/2✓ Branch 0 taken 441 times.
✗ Branch 1 not taken.
|
441 | add_key_equal_fields(thd, key_fields, *and_level, cond_func, |
| 7412 |
3/6✓ Branch 0 taken 441 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 441 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 434 times.
✗ Branch 5 not taken.
|
441 | (Item_field *)(cond_func->key_item()->real_item()), |
| 7413 | true, cond_func->arguments(), 1, usable_tables, | ||
| 7414 | sargables); | ||
| 7415 |
5/6✓ Branch 0 taken 1119659 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1119526 times.
✓ Branch 3 taken 133 times.
✓ Branch 4 taken 255 times.
✓ Branch 5 taken 1119408 times.
|
2239189 | } else if (cond_func->functype() == Item_func::JSON_CONTAINS || |
| 7416 |
3/4✓ Branch 0 taken 1119530 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 1119413 times.
|
1119526 | cond_func->functype() == Item_func::JSON_OVERLAPS) { |
| 7417 | /* | ||
| 7418 | Applicability analysis was done during substitute_gc(). | ||
| 7419 | Check here that a typed array field is used and there's a key over | ||
| 7420 | it. | ||
| 7421 | 1) func has a key item | ||
| 7422 | 2) key item is a local field | ||
| 7423 | 3) key item is a typed array field | ||
| 7424 | If so, mark appropriate index as available for range optimizer | ||
| 7425 | */ | ||
| 7426 |
1/2✓ Branch 0 taken 255 times.
✗ Branch 1 not taken.
|
255 | if (!cond_func->key_item() || // 1 |
| 7427 |
8/10✓ Branch 0 taken 244 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 244 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 212 times.
✓ Branch 7 taken 32 times.
✓ Branch 8 taken 43 times.
✓ Branch 9 taken 212 times.
|
467 | !is_local_field(cond_func->key_item()) || // 2 |
| 7428 |
3/6✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 212 times.
|
212 | !cond_func->key_item()->returns_array()) // 3 |
| 7429 | 43 | break; | |
| 7430 | const Field *field = | ||
| 7431 |
1/2✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
|
212 | (down_cast<const Item_field *>(cond_func->key_item()))->field; |
| 7432 | 212 | JOIN_TAB *tab = field->table->reginfo.join_tab; | |
| 7433 | 212 | Key_map possible_keys = field->key_start; | |
| 7434 | |||
| 7435 | 212 | possible_keys.intersect(field->table->keys_in_use_for_query); | |
| 7436 | 212 | tab->keys().merge(possible_keys); // Add possible keys | |
| 7437 | 212 | tab->const_keys.merge(possible_keys); // Add possible keys | |
| 7438 | } // if (... Item_func::CONTAINS) | ||
| 7439 | // The predicate is IN or <> | ||
| 7440 |
6/8✓ Branch 0 taken 1119403 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1119417 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 420576 times.
✓ Branch 5 taken 698841 times.
✓ Branch 6 taken 420557 times.
✓ Branch 7 taken 698860 times.
|
1539984 | else if (is_local_field(cond_func->key_item()) && |
| 7441 |
3/4✓ Branch 0 taken 420576 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 420557 times.
✓ Branch 3 taken 19 times.
|
420576 | !cond_func->is_outer_reference()) { |
| 7442 |
1/2✓ Branch 0 taken 420557 times.
✗ Branch 1 not taken.
|
420557 | values = cond_func->arguments() + 1; |
| 7443 |
5/6✓ Branch 0 taken 420557 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 252625 times.
✓ Branch 3 taken 167932 times.
✓ Branch 4 taken 844 times.
✓ Branch 5 taken 419713 times.
|
673182 | if (cond_func->functype() == Item_func::NE_FUNC && |
| 7444 |
4/6✓ Branch 0 taken 252625 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 252625 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 844 times.
✓ Branch 5 taken 251781 times.
|
252625 | is_local_field(cond_func->arguments()[1])) |
| 7445 | 844 | values--; | |
| 7446 |
5/8✓ Branch 0 taken 420557 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 167932 times.
✓ Branch 3 taken 252625 times.
✓ Branch 4 taken 167932 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 167932 times.
|
420557 | assert(cond_func->functype() != Item_func::IN_FUNC || |
| 7447 | cond_func->argument_count() != 2); | ||
| 7448 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 420557 times.
|
420557 | if (add_key_equal_fields( |
| 7449 | thd, key_fields, *and_level, cond_func, | ||
| 7450 |
2/4✓ Branch 0 taken 420557 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 420557 times.
✗ Branch 3 not taken.
|
420557 | (Item_field *)(cond_func->key_item()->real_item()), false, |
| 7451 |
2/4✓ Branch 0 taken 420557 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 420557 times.
✗ Branch 3 not taken.
|
420557 | values, cond_func->argument_count() - 1, usable_tables, |
| 7452 | sargables)) | ||
| 7453 | ✗ | return true; | |
| 7454 |
5/6✓ Branch 0 taken 698849 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 962 times.
✓ Branch 3 taken 697887 times.
✓ Branch 4 taken 229 times.
✓ Branch 5 taken 698620 times.
|
699822 | } else if (cond_func->functype() == Item_func::IN_FUNC && |
| 7455 |
4/6✓ Branch 0 taken 962 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 962 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 229 times.
✓ Branch 5 taken 733 times.
|
962 | cond_func->key_item()->type() == Item::ROW_ITEM) { |
| 7456 | /* | ||
| 7457 | The condition is (column1, column2, ... ) IN ((const1_1, const1_2), | ||
| 7458 | ...) and there is an index on (column1, column2, ...) | ||
| 7459 | |||
| 7460 | The code below makes sure that the row constructor on the lhs indeed | ||
| 7461 | contains only column references before calling add_key_field on them. | ||
| 7462 | |||
| 7463 | We can't do a ref access on IN, yet here we are. Why? We need | ||
| 7464 | to run add_key_field() only because it verifies that there are | ||
| 7465 | only constant expressions in the rows on the IN's rhs, see | ||
| 7466 | comment above the call to add_key_field() below. | ||
| 7467 | |||
| 7468 | Actually, We could in theory do a ref access if the IN rhs | ||
| 7469 | contained just a single row, but there is a hack in the parser | ||
| 7470 | causing such IN predicates be parsed as row equalities. | ||
| 7471 | */ | ||
| 7472 |
1/2✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
|
229 | Item_row *lhs_row = static_cast<Item_row *>(cond_func->key_item()); |
| 7473 |
3/4✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 205 times.
✓ Branch 3 taken 24 times.
|
229 | if (is_row_of_local_columns(lhs_row)) { |
| 7474 |
3/4✓ Branch 0 taken 664 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 459 times.
✓ Branch 3 taken 205 times.
|
664 | for (uint i = 0; i < lhs_row->cols(); ++i) { |
| 7475 |
2/4✓ Branch 0 taken 459 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 459 times.
✗ Branch 3 not taken.
|
459 | Item *const lhs_item = lhs_row->element_index(i)->real_item(); |
| 7476 |
2/4✓ Branch 0 taken 459 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 459 times.
|
459 | assert(lhs_item->type() == Item::FIELD_ITEM); |
| 7477 | 459 | Item_field *const lhs_column = static_cast<Item_field *>(lhs_item); | |
| 7478 | // j goes from 1 since arguments()[0] is the lhs of IN. | ||
| 7479 |
3/4✓ Branch 0 taken 1425 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 966 times.
✓ Branch 3 taken 459 times.
|
1425 | for (uint j = 1; j < cond_func->argument_count(); ++j) { |
| 7480 | // Here we pick out the i:th column in the j:th row. | ||
| 7481 |
1/2✓ Branch 0 taken 966 times.
✗ Branch 1 not taken.
|
966 | Item *rhs_item = cond_func->arguments()[j]; |
| 7482 |
2/4✓ Branch 0 taken 966 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 966 times.
|
966 | assert(rhs_item->type() == Item::ROW_ITEM); |
| 7483 | 966 | Item_row *rhs_row = static_cast<Item_row *>(rhs_item); | |
| 7484 |
3/6✓ Branch 0 taken 966 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 966 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 966 times.
|
966 | assert(rhs_row->cols() == lhs_row->cols()); |
| 7485 |
1/2✓ Branch 0 taken 966 times.
✗ Branch 1 not taken.
|
966 | Item **rhs_expr_ptr = rhs_row->addr(i); |
| 7486 | /* | ||
| 7487 | add_key_field() will write a Key_field on each call | ||
| 7488 | here, but we don't care, it will never be used. We only | ||
| 7489 | call it for the side effect: update JOIN_TAB::const_keys | ||
| 7490 | so the range optimizer can be invoked. We pass a | ||
| 7491 | scrap buffer and pointer here. | ||
| 7492 | */ | ||
| 7493 | 966 | Key_field scrap_key_field = **key_fields; | |
| 7494 | 966 | Key_field *scrap_key_field_ptr = &scrap_key_field; | |
| 7495 |
2/4✓ Branch 0 taken 966 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 966 times.
|
966 | if (add_key_field(thd, &scrap_key_field_ptr, *and_level, |
| 7496 | cond_func, lhs_column, | ||
| 7497 | true, // eq_func | ||
| 7498 | rhs_expr_ptr, | ||
| 7499 | 1, // Number of expressions: one | ||
| 7500 | usable_tables, | ||
| 7501 | nullptr)) // sargables | ||
| 7502 | ✗ | return true; | |
| 7503 | // The pointer is not supposed to increase by more than one. | ||
| 7504 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 966 times.
|
966 | assert(scrap_key_field_ptr <= &scrap_key_field + 1); |
| 7505 | } | ||
| 7506 | } | ||
| 7507 | } | ||
| 7508 | } | ||
| 7509 | 1127143 | break; | |
| 7510 | } | ||
| 7511 | 413648 | case Item_func::OPTIMIZE_OP: { | |
| 7512 |
3/4✓ Branch 0 taken 413648 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 195020 times.
✓ Branch 3 taken 218628 times.
|
608669 | bool equal_func = (cond_func->functype() == Item_func::EQ_FUNC || |
| 7513 |
3/4✓ Branch 0 taken 195021 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2201 times.
✓ Branch 3 taken 192820 times.
|
195020 | cond_func->functype() == Item_func::EQUAL_FUNC); |
| 7514 | |||
| 7515 |
4/6✓ Branch 0 taken 413649 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 413649 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 400226 times.
✓ Branch 5 taken 13423 times.
|
413649 | if (is_local_field(cond_func->arguments()[0])) { |
| 7516 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 400225 times.
|
400225 | if (add_key_equal_fields( |
| 7517 | thd, key_fields, *and_level, cond_func, | ||
| 7518 |
2/4✓ Branch 0 taken 400226 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 400225 times.
✗ Branch 3 not taken.
|
400226 | (Item_field *)(cond_func->arguments()[0])->real_item(), |
| 7519 |
2/4✓ Branch 0 taken 400225 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 400226 times.
✗ Branch 3 not taken.
|
400226 | equal_func, cond_func->arguments() + 1, 1, usable_tables, |
| 7520 | sargables)) | ||
| 7521 | ✗ | return true; | |
| 7522 | } else { | ||
| 7523 |
2/4✓ Branch 0 taken 13423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13423 times.
✗ Branch 3 not taken.
|
13423 | Item *real_item = cond_func->arguments()[0]->real_item(); |
| 7524 |
3/4✓ Branch 0 taken 13423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11437 times.
✓ Branch 3 taken 1986 times.
|
13423 | if (real_item->type() == Item::FUNC_ITEM) { |
| 7525 | 11437 | Item_func *func_item = down_cast<Item_func *>(real_item); | |
| 7526 |
3/4✓ Branch 0 taken 11437 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3937 times.
✓ Branch 3 taken 7500 times.
|
11437 | if (func_item->functype() == Item_func::COLLATE_FUNC) { |
| 7527 |
1/2✓ Branch 0 taken 3937 times.
✗ Branch 1 not taken.
|
3937 | Item *key_item = func_item->key_item(); |
| 7528 |
3/4✓ Branch 0 taken 3937 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3904 times.
✓ Branch 3 taken 33 times.
|
3937 | if (key_item->type() == Item::FIELD_ITEM) { |
| 7529 |
2/4✓ Branch 0 taken 3904 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3904 times.
|
3904 | if (add_key_equal_fields(thd, key_fields, *and_level, cond_func, |
| 7530 | down_cast<Item_field *>(key_item), | ||
| 7531 |
1/2✓ Branch 0 taken 3904 times.
✗ Branch 1 not taken.
|
3904 | equal_func, cond_func->arguments() + 1, |
| 7532 | 1, usable_tables, sargables)) | ||
| 7533 | ✗ | return true; | |
| 7534 | } | ||
| 7535 | } | ||
| 7536 | } | ||
| 7537 | } | ||
| 7538 |
6/8✓ Branch 0 taken 413648 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 413649 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30199 times.
✓ Branch 5 taken 383450 times.
✓ Branch 6 taken 30199 times.
✓ Branch 7 taken 383450 times.
|
443847 | if (is_local_field(cond_func->arguments()[1]) && |
| 7539 |
2/4✓ Branch 0 taken 30199 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30199 times.
✗ Branch 3 not taken.
|
30199 | cond_func->functype() != Item_func::LIKE_FUNC) { |
| 7540 |
2/4✓ Branch 0 taken 30199 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30199 times.
|
60398 | if (add_key_equal_fields( |
| 7541 | thd, key_fields, *and_level, cond_func, | ||
| 7542 |
3/6✓ Branch 0 taken 30199 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30199 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30199 times.
✗ Branch 5 not taken.
|
30199 | (Item_field *)(cond_func->arguments()[1])->real_item(), |
| 7543 | equal_func, cond_func->arguments(), 1, usable_tables, | ||
| 7544 | sargables)) | ||
| 7545 | ✗ | return true; | |
| 7546 | } else { | ||
| 7547 |
2/4✓ Branch 0 taken 383449 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 383449 times.
✗ Branch 3 not taken.
|
383450 | Item *real_item = cond_func->arguments()[1]->real_item(); |
| 7548 |
3/4✓ Branch 0 taken 383449 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11147 times.
✓ Branch 3 taken 372302 times.
|
383449 | if (real_item->type() == Item::FUNC_ITEM) { |
| 7549 | 11147 | Item_func *func_item = down_cast<Item_func *>(real_item); | |
| 7550 |
3/4✓ Branch 0 taken 11147 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91 times.
✓ Branch 3 taken 11056 times.
|
11147 | if (func_item->functype() == Item_func::COLLATE_FUNC) { |
| 7551 |
1/2✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
|
91 | Item *key_item = func_item->key_item(); |
| 7552 |
3/4✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 54 times.
|
91 | if (key_item->type() == Item::FIELD_ITEM) { |
| 7553 |
3/6✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
|
37 | if (add_key_equal_fields(thd, key_fields, *and_level, cond_func, |
| 7554 | down_cast<Item_field *>(key_item), | ||
| 7555 | equal_func, cond_func->arguments(), 1, | ||
| 7556 | usable_tables, sargables)) | ||
| 7557 | ✗ | return true; | |
| 7558 | } | ||
| 7559 | } | ||
| 7560 | } | ||
| 7561 | } | ||
| 7562 | |||
| 7563 | 413648 | break; | |
| 7564 | } | ||
| 7565 | 17266 | case Item_func::OPTIMIZE_NULL: | |
| 7566 | /* column_name IS [NOT] NULL */ | ||
| 7567 |
6/8✓ Branch 0 taken 17266 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17266 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16284 times.
✓ Branch 5 taken 982 times.
✓ Branch 6 taken 16284 times.
✓ Branch 7 taken 982 times.
|
33550 | if (is_local_field(cond_func->arguments()[0]) && |
| 7568 |
2/4✓ Branch 0 taken 16284 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16284 times.
✗ Branch 3 not taken.
|
16284 | !cond_func->is_outer_reference()) { |
| 7569 |
2/4✓ Branch 0 taken 16284 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16284 times.
✗ Branch 3 not taken.
|
16284 | Item *tmp = new Item_null; |
| 7570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16284 times.
|
16284 | if (tmp == nullptr) return true; |
| 7571 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16284 times.
|
16284 | if (add_key_equal_fields( |
| 7572 | thd, key_fields, *and_level, cond_func, | ||
| 7573 |
2/4✓ Branch 0 taken 16284 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16284 times.
✗ Branch 3 not taken.
|
16284 | (Item_field *)(cond_func->arguments()[0])->real_item(), |
| 7574 |
2/4✓ Branch 0 taken 16284 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16284 times.
✗ Branch 3 not taken.
|
16284 | cond_func->functype() == Item_func::ISNULL_FUNC, &tmp, 1, |
| 7575 | usable_tables, sargables)) | ||
| 7576 | ✗ | return true; | |
| 7577 | } | ||
| 7578 | 17266 | break; | |
| 7579 | 3137157 | case Item_func::OPTIMIZE_EQUAL: | |
| 7580 | 3137157 | Item_equal *item_equal = (Item_equal *)cond; | |
| 7581 | 3137157 | Item *const_item = item_equal->get_const(); | |
| 7582 |
2/2✓ Branch 0 taken 1227086 times.
✓ Branch 1 taken 1910061 times.
|
3137147 | if (const_item) { |
| 7583 | /* | ||
| 7584 | For each field field1 from item_equal consider the equality | ||
| 7585 | field1=const_item as a condition allowing an index access of the table | ||
| 7586 | with field1 by the keys value of field1. | ||
| 7587 | */ | ||
| 7588 |
5/8✓ Branch 0 taken 1227086 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1227096 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2569570 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1342475 times.
✓ Branch 7 taken 1227095 times.
|
2569560 | for (Item_field &item : item_equal->get_fields()) { |
| 7589 |
2/4✓ Branch 0 taken 1342474 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1342474 times.
|
1342476 | if (add_key_field(thd, key_fields, *and_level, cond_func, &item, true, |
| 7590 | &const_item, 1, usable_tables, sargables)) | ||
| 7591 | ✗ | return true; | |
| 7592 | } | ||
| 7593 | } else { | ||
| 7594 | /* | ||
| 7595 | Consider all pairs of different fields included into item_equal. | ||
| 7596 | For each of them (field1, field1) consider the equality | ||
| 7597 | field1=field2 as a condition allowing an index access of the table | ||
| 7598 | with field1 by the keys value of field2. | ||
| 7599 | */ | ||
| 7600 |
5/8✓ Branch 0 taken 1910068 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1910067 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5752785 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3842720 times.
✓ Branch 7 taken 1910065 times.
|
5752784 | for (Item_field &outer : item_equal->get_fields()) { |
| 7601 |
5/8✓ Branch 0 taken 3842731 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3842721 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12403482 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8560759 times.
✓ Branch 7 taken 3842723 times.
|
12403463 | for (Item_field &inner : item_equal->get_fields()) { |
| 7602 |
3/4✓ Branch 0 taken 8560741 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4718038 times.
✓ Branch 3 taken 3842703 times.
|
8560760 | if (!outer.field->eq(inner.field)) { |
| 7603 | 4718038 | Item *inner_ptr = &inner; | |
| 7604 |
2/4✓ Branch 0 taken 4718037 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4718037 times.
|
4718038 | if (add_key_field(thd, key_fields, *and_level, cond_func, &outer, |
| 7605 | true, &inner_ptr, 1, usable_tables, sargables)) | ||
| 7606 | ✗ | return true; | |
| 7607 | } | ||
| 7608 | } | ||
| 7609 | } | ||
| 7610 | } | ||
| 7611 | 3137160 | break; | |
| 7612 | } | ||
| 7613 | 4931229 | return false; | |
| 7614 | } | ||
| 7615 | |||
| 7616 | /* | ||
| 7617 | Add all keys with uses 'field' for some keypart | ||
| 7618 | If field->and_level != and_level then only mark key_part as const_part | ||
| 7619 | |||
| 7620 | RETURN | ||
| 7621 | 0 - OK | ||
| 7622 | 1 - Out of memory. | ||
| 7623 | */ | ||
| 7624 | |||
| 7625 | 4828428 | static bool add_key_part(Key_use_array *keyuse_array, Key_field *key_field) { | |
| 7626 |
3/4✓ Branch 0 taken 4828430 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4828181 times.
✓ Branch 3 taken 249 times.
|
4828428 | if (key_field->eq_func && !(key_field->optimize & KEY_OPTIMIZE_EXISTS)) { |
| 7627 | 4828181 | const Field *const field = key_field->item_field->field; | |
| 7628 | 4828181 | TABLE_LIST *const tl = key_field->item_field->table_ref; | |
| 7629 | 4828181 | TABLE *const table = tl->table; | |
| 7630 | |||
| 7631 |
2/2✓ Branch 0 taken 17861920 times.
✓ Branch 1 taken 4828185 times.
|
22690105 | for (uint key = 0; key < table->s->keys; key++) { |
| 7632 |
2/2✓ Branch 0 taken 25563 times.
✓ Branch 1 taken 17836360 times.
|
17861920 | if (!(table->keys_in_use_for_query.is_set(key))) continue; |
| 7633 |
2/2✓ Branch 0 taken 522 times.
✓ Branch 1 taken 17835838 times.
|
17836360 | if (table->key_info[key].flags & (HA_FULLTEXT | HA_SPATIAL)) |
| 7634 | 522 | continue; // ToDo: ft-keys in non-ft queries. SerG | |
| 7635 | |||
| 7636 | 17835838 | uint key_parts = actual_key_parts(&table->key_info[key]); | |
| 7637 |
2/2✓ Branch 0 taken 31205414 times.
✓ Branch 1 taken 17835839 times.
|
49041253 | for (uint part = 0; part < key_parts; part++) { |
| 7638 |
2/2✓ Branch 0 taken 7130869 times.
✓ Branch 1 taken 24074582 times.
|
31205414 | if (field->eq(table->key_info[key].key_part[part].field)) { |
| 7639 | const Key_use keyuse(tl, key_field->val, | ||
| 7640 | 7130869 | key_field->val->used_tables(), key, part, | |
| 7641 | 7130869 | key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL, | |
| 7642 | (key_part_map)1 << part, | ||
| 7643 | ~(ha_rows)0, // will be set in optimize_keyuse | ||
| 7644 | 7130869 | key_field->null_rejecting, key_field->cond_guard, | |
| 7645 |
1/2✓ Branch 0 taken 7130827 times.
✗ Branch 1 not taken.
|
7130869 | key_field->sj_pred_no); |
| 7646 |
2/4✓ Branch 0 taken 7130815 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7130815 times.
|
7130819 | if (keyuse_array->push_back(keyuse)) |
| 7647 | ✗ | return true; /* purecov: inspected */ | |
| 7648 | } | ||
| 7649 | } | ||
| 7650 | } | ||
| 7651 | } | ||
| 7652 | 4828432 | return false; | |
| 7653 | } | ||
| 7654 | |||
| 7655 | /** | ||
| 7656 | Function parses WHERE condition and add key_use for FT index | ||
| 7657 | into key_use array if suitable MATCH function is found. | ||
| 7658 | Condition should be a set of AND expression, OR is not supported. | ||
| 7659 | MATCH function should be a part of simple expression. | ||
| 7660 | Simple expression is MATCH only function or MATCH is a part of | ||
| 7661 | comparison expression ('>=' or '>' operations are supported). | ||
| 7662 | It also sets FT_HINTS values(op_type, op_value). | ||
| 7663 | |||
| 7664 | @param keyuse_array Key_use array | ||
| 7665 | @param cond WHERE condition | ||
| 7666 | @param usable_tables usable tables | ||
| 7667 | @param simple_match_expr true if this is the first call false otherwise. | ||
| 7668 | if MATCH function is found at first call it means | ||
| 7669 | that MATCH is simple expression, otherwise, in case | ||
| 7670 | of AND/OR condition this parameter will be false. | ||
| 7671 | |||
| 7672 | @retval | ||
| 7673 | true if FT key was added to Key_use array | ||
| 7674 | @retval | ||
| 7675 | false if no key was added to Key_use array | ||
| 7676 | |||
| 7677 | */ | ||
| 7678 | |||
| 7679 | 2465 | static bool add_ft_keys(Key_use_array *keyuse_array, Item *cond, | |
| 7680 | table_map usable_tables, bool simple_match_expr) { | ||
| 7681 | 2465 | Item_func_match *cond_func = nullptr; | |
| 7682 | |||
| 7683 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2457 times.
|
2465 | if (!cond) return false; |
| 7684 | |||
| 7685 |
2/4✓ Branch 0 taken 2457 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2457 times.
|
2457 | assert(cond->is_bool_func()); |
| 7686 | |||
| 7687 |
3/4✓ Branch 0 taken 2457 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2336 times.
✓ Branch 3 taken 121 times.
|
2457 | if (cond->type() == Item::FUNC_ITEM) { |
| 7688 | 2336 | Item_func *func = down_cast<Item_func *>(cond); | |
| 7689 |
1/2✓ Branch 0 taken 2336 times.
✗ Branch 1 not taken.
|
2336 | Item_func::Functype functype = func->functype(); |
| 7690 |
2/2✓ Branch 0 taken 2153 times.
✓ Branch 1 taken 183 times.
|
2336 | if (functype == Item_func::MATCH_FUNC) { |
| 7691 |
1/2✓ Branch 0 taken 2153 times.
✗ Branch 1 not taken.
|
2153 | func = down_cast<Item_func *>(func->arguments()[0]); |
| 7692 |
1/2✓ Branch 0 taken 2153 times.
✗ Branch 1 not taken.
|
2153 | functype = func->functype(); |
| 7693 | } | ||
| 7694 | 2336 | enum ft_operation op_type = FT_OP_NO; | |
| 7695 | 2336 | double op_value = 0.0; | |
| 7696 |
2/2✓ Branch 0 taken 2153 times.
✓ Branch 1 taken 183 times.
|
2336 | if (functype == Item_func::FT_FUNC) { |
| 7697 |
1/2✓ Branch 0 taken 2153 times.
✗ Branch 1 not taken.
|
2153 | cond_func = down_cast<Item_func_match *>(func)->get_master(); |
| 7698 | 2153 | cond_func->set_hints_op(op_type, op_value); | |
| 7699 |
2/2✓ Branch 0 taken 93 times.
✓ Branch 1 taken 90 times.
|
183 | } else if (func->arg_count == 2) { |
| 7700 |
1/2✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
|
93 | Item *arg0 = func->arguments()[0]; |
| 7701 |
1/2✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
|
93 | Item *arg1 = func->arguments()[1]; |
| 7702 |
10/12✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 65 times.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17 times.
✓ Branch 7 taken 11 times.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 13 times.
✓ Branch 10 taken 15 times.
✓ Branch 11 taken 78 times.
|
110 | if (arg1->const_item() && is_function_of_type(arg0, Item_func::FT_FUNC) && |
| 7703 | 4 | ((functype == Item_func::GE_FUNC && | |
| 7704 |
5/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 2 times.
|
17 | (op_value = arg1->val_real()) > 0) || |
| 7705 | 13 | (functype == Item_func::GT_FUNC && | |
| 7706 |
2/4✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | (op_value = arg1->val_real()) >= 0))) { |
| 7707 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | cond_func = down_cast<Item_func_match *>(arg0)->get_master(); |
| 7708 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 13 times.
|
15 | if (functype == Item_func::GE_FUNC) |
| 7709 | 2 | op_type = FT_OP_GE; | |
| 7710 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | else if (functype == Item_func::GT_FUNC) |
| 7711 | 13 | op_type = FT_OP_GT; | |
| 7712 | 15 | cond_func->set_hints_op(op_type, op_value); | |
| 7713 |
1/2✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
|
78 | } else if (arg0->const_item() && |
| 7714 |
9/10✓ Branch 0 taken 55 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 45 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 70 times.
|
88 | is_function_of_type(arg1, Item_func::FT_FUNC) && |
| 7715 | 6 | ((functype == Item_func::LE_FUNC && | |
| 7716 |
5/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 2 times.
|
10 | (op_value = arg0->val_real()) > 0) || |
| 7717 | 4 | (functype == Item_func::LT_FUNC && | |
| 7718 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | (op_value = arg0->val_real()) >= 0))) { |
| 7719 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | cond_func = down_cast<Item_func_match *>(arg1)->get_master(); |
| 7720 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | if (functype == Item_func::LE_FUNC) |
| 7721 | 4 | op_type = FT_OP_GE; | |
| 7722 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | else if (functype == Item_func::LT_FUNC) |
| 7723 | 4 | op_type = FT_OP_GT; | |
| 7724 | 8 | cond_func->set_hints_op(op_type, op_value); | |
| 7725 | } | ||
| 7726 | } | ||
| 7727 |
2/4✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
|
121 | } else if (cond->type() == Item::COND_ITEM) { |
| 7728 |
1/2✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
|
121 | List_iterator_fast<Item> li(*down_cast<Item_cond *>(cond)->argument_list()); |
| 7729 | |||
| 7730 |
3/4✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 4 times.
|
121 | if (down_cast<Item_cond *>(cond)->functype() == Item_func::COND_AND_FUNC) { |
| 7731 | Item *item; | ||
| 7732 |
2/2✓ Branch 0 taken 253 times.
✓ Branch 1 taken 117 times.
|
370 | while ((item = li++)) |
| 7733 |
2/4✓ Branch 0 taken 253 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 253 times.
|
253 | if (add_ft_keys(keyuse_array, item, usable_tables, false)) return true; |
| 7734 | } | ||
| 7735 | } | ||
| 7736 | |||
| 7737 |
6/6✓ Branch 0 taken 2176 times.
✓ Branch 1 taken 281 times.
✓ Branch 2 taken 2155 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 307 times.
✓ Branch 5 taken 2150 times.
|
4612 | if (!cond_func || cond_func->key == NO_SUCH_KEY || |
| 7738 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2150 times.
|
2155 | !(usable_tables & cond_func->table_ref->map())) |
| 7739 | 307 | return false; | |
| 7740 | |||
| 7741 | 2150 | TABLE_LIST *tbl = cond_func->table_ref; | |
| 7742 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2148 times.
|
2150 | if (!tbl->table->keys_in_use_for_query.is_set(cond_func->key)) return false; |
| 7743 | |||
| 7744 | 2148 | cond_func->set_simple_expression(simple_match_expr); | |
| 7745 | |||
| 7746 | 4296 | const Key_use keyuse(tbl, cond_func, cond_func->key_item()->used_tables(), | |
| 7747 | cond_func->key, FT_KEYPART, | ||
| 7748 | 0, // optimize | ||
| 7749 | 0, // keypart_map | ||
| 7750 | ~(ha_rows)0, // ref_table_rows | ||
| 7751 | false, // null_rejecting | ||
| 7752 | nullptr, // cond_guard | ||
| 7753 |
1/2✓ Branch 0 taken 2148 times.
✗ Branch 1 not taken.
|
2148 | UINT_MAX); // sj_pred_no |
| 7754 | 2148 | tbl->table->reginfo.join_tab->keys().set_bit(cond_func->key); | |
| 7755 |
1/2✓ Branch 0 taken 2148 times.
✗ Branch 1 not taken.
|
2148 | return keyuse_array->push_back(keyuse); |
| 7756 | } | ||
| 7757 | |||
| 7758 | /** | ||
| 7759 | Compares two keyuse elements. | ||
| 7760 | |||
| 7761 | @param a first Key_use element | ||
| 7762 | @param b second Key_use element | ||
| 7763 | |||
| 7764 | Compare Key_use elements so that they are sorted as follows: | ||
| 7765 | -# By table. | ||
| 7766 | -# By key for each table. | ||
| 7767 | -# By keypart for each key. | ||
| 7768 | -# Const values. | ||
| 7769 | -# Ref_or_null. | ||
| 7770 | |||
| 7771 | @retval true If a < b. | ||
| 7772 | @retval false If a >= b. | ||
| 7773 | */ | ||
| 7774 | 34595261 | static bool sort_keyuse(const Key_use &a, const Key_use &b) { | |
| 7775 |
2/2✓ Branch 0 taken 21194410 times.
✓ Branch 1 taken 13400880 times.
|
34595261 | if (a.table_ref->tableno() != b.table_ref->tableno()) |
| 7776 | 21194410 | return a.table_ref->tableno() < b.table_ref->tableno(); | |
| 7777 |
2/2✓ Branch 0 taken 9352938 times.
✓ Branch 1 taken 4047942 times.
|
13400880 | if (a.key != b.key) return a.key < b.key; |
| 7778 |
2/2✓ Branch 0 taken 1167849 times.
✓ Branch 1 taken 2880093 times.
|
4047942 | if (a.keypart != b.keypart) return a.keypart < b.keypart; |
| 7779 | // Place const values before other ones | ||
| 7780 | 2880093 | bool a_const = a.used_tables & ~OUTER_REF_TABLE_BIT; | |
| 7781 | 2880093 | bool b_const = b.used_tables & ~OUTER_REF_TABLE_BIT; | |
| 7782 |
2/2✓ Branch 0 taken 87 times.
✓ Branch 1 taken 2880006 times.
|
2880093 | if (a_const != b_const) return b_const; |
| 7783 | /* Place rows that are not 'OPTIMIZE_REF_OR_NULL' first */ | ||
| 7784 | 2880006 | return (a.optimize & KEY_OPTIMIZE_REF_OR_NULL) < | |
| 7785 | 2880006 | (b.optimize & KEY_OPTIMIZE_REF_OR_NULL); | |
| 7786 | } | ||
| 7787 | |||
| 7788 | /* | ||
| 7789 | Add to Key_field array all 'ref' access candidates within nested join. | ||
| 7790 | |||
| 7791 | This function populates Key_field array with entries generated from the | ||
| 7792 | ON condition of the given nested join, and does the same for nested joins | ||
| 7793 | contained within this nested join. | ||
| 7794 | |||
| 7795 | @param thd session context | ||
| 7796 | @param[in] nested_join_table Nested join pseudo-table to process | ||
| 7797 | @param[in,out] end End of the key field array | ||
| 7798 | @param[in,out] and_level And-level | ||
| 7799 | @param[in,out] sargables Array of found sargable candidates | ||
| 7800 | |||
| 7801 | @returns false if success, true if error | ||
| 7802 | |||
| 7803 | @note | ||
| 7804 | We can add accesses to the tables that are direct children of this nested | ||
| 7805 | join (1), and are not inner tables w.r.t their neighbours (2). | ||
| 7806 | |||
| 7807 | Example for #1 (outer brackets pair denotes nested join this function is | ||
| 7808 | invoked for): | ||
| 7809 | @code | ||
| 7810 | ... LEFT JOIN (t1 LEFT JOIN (t2 ... ) ) ON cond | ||
| 7811 | @endcode | ||
| 7812 | Example for #2: | ||
| 7813 | @code | ||
| 7814 | ... LEFT JOIN (t1 LEFT JOIN t2 ) ON cond | ||
| 7815 | @endcode | ||
| 7816 | In examples 1-2 for condition cond, we can add 'ref' access candidates to | ||
| 7817 | t1 only. | ||
| 7818 | Example #3: | ||
| 7819 | @code | ||
| 7820 | ... LEFT JOIN (t1, t2 LEFT JOIN t3 ON inner_cond) ON cond | ||
| 7821 | @endcode | ||
| 7822 | Here we can add 'ref' access candidates for t1 and t2, but not for t3. | ||
| 7823 | */ | ||
| 7824 | |||
| 7825 | 6092 | static bool add_key_fields_for_nj(THD *thd, JOIN *join, | |
| 7826 | TABLE_LIST *nested_join_table, | ||
| 7827 | Key_field **end, uint *and_level, | ||
| 7828 | SARGABLE_PARAM **sargables) { | ||
| 7829 | 6092 | mem_root_deque<TABLE_LIST *> &join_list = | |
| 7830 | 6092 | nested_join_table->nested_join->join_list; | |
| 7831 |
1/2✓ Branch 0 taken 6092 times.
✗ Branch 1 not taken.
|
6092 | auto li = join_list.begin(); |
| 7832 |
1/2✓ Branch 0 taken 6092 times.
✗ Branch 1 not taken.
|
6092 | auto li_end = join_list.end(); |
| 7833 |
1/2✓ Branch 0 taken 6092 times.
✗ Branch 1 not taken.
|
6092 | auto li2 = join_list.begin(); |
| 7834 |
1/2✓ Branch 0 taken 6092 times.
✗ Branch 1 not taken.
|
6092 | auto li2_end = join_list.end(); |
| 7835 | 6092 | bool have_another = false; | |
| 7836 | 6092 | table_map tables = 0; | |
| 7837 | TABLE_LIST *table; | ||
| 7838 | |||
| 7839 |
9/12✓ Branch 0 taken 21846 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15729 times.
✓ Branch 3 taken 6117 times.
✓ Branch 4 taken 15729 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15729 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6117 times.
✓ Branch 9 taken 15729 times.
✓ Branch 10 taken 25 times.
✓ Branch 11 taken 6092 times.
|
21871 | while ((table = (li != li_end) ? *li++ : nullptr) || |
| 7840 |
3/6✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
|
25 | (have_another && li2 != join_list.end() && |
| 7841 | 25 | (li = li2, li_end = li2_end, have_another = false, | |
| 7842 |
7/12✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 25 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 15754 times.
✓ Branch 11 taken 6092 times.
|
21871 | (li != li_end) && (table = *li++)))) { |
| 7843 |
2/2✓ Branch 0 taken 158 times.
✓ Branch 1 taken 15596 times.
|
15754 | if (table->nested_join) { |
| 7844 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 133 times.
|
158 | if (!table->join_cond_optim()) { |
| 7845 | /* It's a semi-join nest. Walk into it as if it wasn't a nest */ | ||
| 7846 | 25 | have_another = true; | |
| 7847 | 25 | li2 = li; | |
| 7848 | 25 | li2_end = li_end; | |
| 7849 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | li = table->nested_join->join_list.begin(); |
| 7850 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | li_end = table->nested_join->join_list.end(); |
| 7851 | } else { | ||
| 7852 |
2/4✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133 times.
|
133 | if (add_key_fields_for_nj(thd, join, table, end, and_level, sargables)) |
| 7853 | ✗ | return true; | |
| 7854 | } | ||
| 7855 |
2/2✓ Branch 0 taken 11391 times.
✓ Branch 1 taken 4205 times.
|
15596 | } else if (!table->join_cond_optim()) |
| 7856 | 11391 | tables |= table->map(); | |
| 7857 | } | ||
| 7858 |
2/2✓ Branch 0 taken 1852 times.
✓ Branch 1 taken 4240 times.
|
6092 | if (nested_join_table->join_cond_optim()) { |
| 7859 |
2/4✓ Branch 0 taken 1852 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1852 times.
|
1852 | if (add_key_fields(thd, join, end, and_level, |
| 7860 | nested_join_table->join_cond_optim(), tables, sargables)) | ||
| 7861 | ✗ | return true; | |
| 7862 | } | ||
| 7863 | 6092 | return false; | |
| 7864 | } | ||
| 7865 | |||
| 7866 | /// @} (end of group RefOptimizerModule) | ||
| 7867 | |||
| 7868 | /** | ||
| 7869 | Check for the presence of AGGFN(DISTINCT a) queries that may be subject | ||
| 7870 | to loose index scan. | ||
| 7871 | |||
| 7872 | |||
| 7873 | Check if the query is a subject to AGGFN(DISTINCT) using loose index scan | ||
| 7874 | (GroupIndexSkipScanIterator). | ||
| 7875 | Optionally (if out_args is supplied) will push the arguments of | ||
| 7876 | AGGFN(DISTINCT) to the list | ||
| 7877 | |||
| 7878 | Check for every COUNT(DISTINCT), AVG(DISTINCT) or | ||
| 7879 | SUM(DISTINCT). These can be resolved by Loose Index Scan as long | ||
| 7880 | as all the aggregate distinct functions refer to the same | ||
| 7881 | fields. Thus: | ||
| 7882 | |||
| 7883 | SELECT AGGFN(DISTINCT a, b), AGGFN(DISTINCT b, a)... => can use LIS | ||
| 7884 | SELECT AGGFN(DISTINCT a), AGGFN(DISTINCT a) ... => can use LIS | ||
| 7885 | SELECT AGGFN(DISTINCT a, b), AGGFN(DISTINCT a) ... => cannot use LIS | ||
| 7886 | SELECT AGGFN(DISTINCT a), AGGFN(DISTINCT b) ... => cannot use LIS | ||
| 7887 | etc. | ||
| 7888 | |||
| 7889 | @param join the join to check | ||
| 7890 | @param[out] out_args Collect the arguments of the aggregate functions | ||
| 7891 | to a list. We don't worry about duplicates as | ||
| 7892 | these will be sorted out later in | ||
| 7893 | get_best_group_min_max. | ||
| 7894 | |||
| 7895 | @return does the query qualify for indexed AGGFN(DISTINCT) | ||
| 7896 | @retval true it does | ||
| 7897 | @retval false AGGFN(DISTINCT) must apply distinct in it. | ||
| 7898 | */ | ||
| 7899 | |||
| 7900 | 2822214 | bool is_indexed_agg_distinct(JOIN *join, | |
| 7901 | mem_root_deque<Item_field *> *out_args) { | ||
| 7902 | Item_sum **sum_item_ptr; | ||
| 7903 | 2822214 | bool result = false; | |
| 7904 |
1/2✓ Branch 0 taken 2822232 times.
✗ Branch 1 not taken.
|
2822214 | Field_map first_aggdistinct_fields; |
| 7905 | |||
| 7906 |
2/2✓ Branch 0 taken 2282923 times.
✓ Branch 1 taken 539309 times.
|
2822232 | if (join->primary_tables > 1 || /* reference more than 1 table */ |
| 7907 |
2/2✓ Branch 0 taken 2280160 times.
✓ Branch 1 taken 2763 times.
|
2282923 | join->select_distinct || /* or a DISTINCT */ |
| 7908 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2280159 times.
|
2280160 | join->query_block->olap == ROLLUP_TYPE) /* Check (B3) for ROLLUP */ |
| 7909 | 542073 | return false; | |
| 7910 | |||
| 7911 |
2/4✓ Branch 0 taken 2280159 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2280159 times.
|
2280159 | if (join->make_sum_func_list(*join->fields, true)) return false; |
| 7912 | |||
| 7913 |
2/2✓ Branch 0 taken 863478 times.
✓ Branch 1 taken 1432650 times.
|
2296128 | for (sum_item_ptr = join->sum_funcs; *sum_item_ptr; sum_item_ptr++) { |
| 7914 | 863478 | Item_sum *sum_item = *sum_item_ptr; | |
| 7915 |
1/2✓ Branch 0 taken 863478 times.
✗ Branch 1 not taken.
|
863478 | Field_map cur_aggdistinct_fields; |
| 7916 | Item *expr; | ||
| 7917 | /* aggregate is not AGGFN(DISTINCT) or more than 1 argument to it */ | ||
| 7918 |
5/6✓ Branch 0 taken 863478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14673 times.
✓ Branch 3 taken 1131 times.
✓ Branch 4 taken 354 times.
✓ Branch 5 taken 847320 times.
|
863478 | switch (sum_item->sum_func()) { |
| 7919 | 14673 | case Item_sum::MIN_FUNC: | |
| 7920 | case Item_sum::MAX_FUNC: | ||
| 7921 | 14673 | continue; | |
| 7922 | 1131 | case Item_sum::COUNT_DISTINCT_FUNC: | |
| 7923 | 1131 | break; | |
| 7924 | 354 | case Item_sum::AVG_DISTINCT_FUNC: | |
| 7925 | case Item_sum::SUM_DISTINCT_FUNC: | ||
| 7926 |
2/4✓ Branch 0 taken 354 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 354 times.
✗ Branch 3 not taken.
|
354 | if (sum_item->argument_count() == 1) break; |
| 7927 | [[fallthrough]]; | ||
| 7928 | default: | ||
| 7929 | 847509 | return false; | |
| 7930 | } | ||
| 7931 | |||
| 7932 |
3/4✓ Branch 0 taken 3062 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1734 times.
✓ Branch 3 taken 1328 times.
|
3062 | for (uint i = 0; i < sum_item->argument_count(); i++) { |
| 7933 |
1/2✓ Branch 0 taken 1734 times.
✗ Branch 1 not taken.
|
1734 | expr = sum_item->get_arg(i); |
| 7934 | /* The AGGFN(DISTINCT) arg is not an attribute? */ | ||
| 7935 |
4/6✓ Branch 0 taken 1734 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1734 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 157 times.
✓ Branch 5 taken 1577 times.
|
1734 | if (expr->real_item()->type() != Item::FIELD_ITEM) return false; |
| 7936 | |||
| 7937 |
1/2✓ Branch 0 taken 1577 times.
✗ Branch 1 not taken.
|
1577 | Item_field *item = static_cast<Item_field *>(expr->real_item()); |
| 7938 |
3/4✓ Branch 0 taken 994 times.
✓ Branch 1 taken 583 times.
✓ Branch 2 taken 994 times.
✗ Branch 3 not taken.
|
1577 | if (out_args) out_args->push_back(item); |
| 7939 | |||
| 7940 | 1577 | cur_aggdistinct_fields.set_bit(item->field->field_index()); | |
| 7941 | 1577 | result = true; | |
| 7942 | } | ||
| 7943 | /* | ||
| 7944 | If there are multiple aggregate functions, make sure that they all | ||
| 7945 | refer to exactly the same set of columns. | ||
| 7946 | */ | ||
| 7947 |
3/4✓ Branch 0 taken 1328 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1078 times.
✓ Branch 3 taken 250 times.
|
1328 | if (first_aggdistinct_fields.is_clear_all()) |
| 7948 |
1/2✓ Branch 0 taken 1078 times.
✗ Branch 1 not taken.
|
1078 | first_aggdistinct_fields.merge(cur_aggdistinct_fields); |
| 7949 |
3/4✓ Branch 0 taken 250 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 218 times.
|
250 | else if (first_aggdistinct_fields != cur_aggdistinct_fields) |
| 7950 | 32 | return false; | |
| 7951 | } | ||
| 7952 | |||
| 7953 | 1432650 | return result; | |
| 7954 | } | ||
| 7955 | |||
| 7956 | /** | ||
| 7957 | Print keys that were appended to join_tab->const_keys because they | ||
| 7958 | can be used for GROUP BY or DISTINCT to the optimizer trace. | ||
| 7959 | |||
| 7960 | @param trace The optimizer trace context we're adding info to | ||
| 7961 | @param join_tab The table the indexes cover | ||
| 7962 | @param new_keys The keys that are considered useful because they can | ||
| 7963 | be used for GROUP BY or DISTINCT | ||
| 7964 | @param cause Zero-terminated string with reason for adding indexes | ||
| 7965 | to const_keys | ||
| 7966 | |||
| 7967 | @see add_group_and_distinct_keys() | ||
| 7968 | */ | ||
| 7969 | 2484 | static void trace_indexes_added_group_distinct(Opt_trace_context *trace, | |
| 7970 | const JOIN_TAB *join_tab, | ||
| 7971 | const Key_map new_keys, | ||
| 7972 | const char *cause) { | ||
| 7973 |
2/2✓ Branch 0 taken 2401 times.
✓ Branch 1 taken 83 times.
|
2484 | if (likely(!trace->is_started())) return; |
| 7974 | |||
| 7975 | 83 | KEY *key_info = join_tab->table()->key_info; | |
| 7976 | 83 | Key_map existing_keys = join_tab->const_keys; | |
| 7977 | 83 | uint nbrkeys = join_tab->table()->s->keys; | |
| 7978 | |||
| 7979 |
1/2✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
|
83 | Opt_trace_object trace_summary(trace, "const_keys_added"); |
| 7980 | { | ||
| 7981 |
1/2✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
|
83 | Opt_trace_array trace_key(trace, "keys"); |
| 7982 |
2/2✓ Branch 0 taken 125 times.
✓ Branch 1 taken 83 times.
|
208 | for (uint j = 0; j < nbrkeys; j++) |
| 7983 |
6/6✓ Branch 0 taken 111 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 110 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 110 times.
✓ Branch 5 taken 15 times.
|
125 | if (new_keys.is_set(j) && !existing_keys.is_set(j)) |
| 7984 |
1/2✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
|
110 | trace_key.add_utf8(key_info[j].name); |
| 7985 | 83 | } | |
| 7986 |
1/2✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
|
83 | trace_summary.add_alnum("cause", cause); |
| 7987 | 83 | } | |
| 7988 | |||
| 7989 | /** | ||
| 7990 | Discover the indexes that might be used for GROUP BY or DISTINCT queries or | ||
| 7991 | indexes that might be used for SKIP SCAN. | ||
| 7992 | |||
| 7993 | If the query has a GROUP BY clause, find all indexes that contain | ||
| 7994 | all GROUP BY fields, and add those indexes to join_tab->const_keys | ||
| 7995 | and join_tab->keys. | ||
| 7996 | |||
| 7997 | If the query has a DISTINCT clause, find all indexes that contain | ||
| 7998 | all SELECT fields, and add those indexes to join_tab->const_keys and | ||
| 7999 | join_tab->keys. This allows later on such queries to be processed by | ||
| 8000 | a GroupIndexSkipScanIterator. | ||
| 8001 | |||
| 8002 | If the query does not have GROUP BY clause or any aggregate function | ||
| 8003 | the function collects possible keys to use for skip scan access. | ||
| 8004 | |||
| 8005 | Note that indexes that are not usable for resolving GROUP | ||
| 8006 | BY/DISTINCT may also be added in some corner cases. For example, an | ||
| 8007 | index covering 'a' and 'b' is not usable for the following query but | ||
| 8008 | is still added: "SELECT DISTINCT a+b FROM t1". This is not a big | ||
| 8009 | issue because a) although the optimizer will consider using the | ||
| 8010 | index, it will not chose it (so minor calculation cost added but not | ||
| 8011 | wrong result) and b) it applies only to corner cases. | ||
| 8012 | |||
| 8013 | @param join the current join | ||
| 8014 | @param join_tab joined table | ||
| 8015 | */ | ||
| 8016 | |||
| 8017 | 3828598 | static void add_loose_index_scan_and_skip_scan_keys(JOIN *join, | |
| 8018 | JOIN_TAB *join_tab) { | ||
| 8019 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3828616 times.
|
3828598 | assert(join_tab->const_keys.is_subset(join_tab->keys())); |
| 8020 | |||
| 8021 | 3828616 | mem_root_deque<Item_field *> indexed_fields(join->thd->mem_root); | |
| 8022 | ORDER *cur_group; | ||
| 8023 | const char *cause; | ||
| 8024 | |||
| 8025 | /* Find the indexes that might be used for skip scan queries. */ | ||
| 8026 |
1/2✓ Branch 0 taken 3828600 times.
✗ Branch 1 not taken.
|
3828601 | if (hint_table_state(join->thd, join_tab->table_ref, SKIP_SCAN_HINT_ENUM, |
| 8027 | 3817398 | OPTIMIZER_SKIP_SCAN) && | |
| 8028 |
6/6✓ Branch 0 taken 3201302 times.
✓ Branch 1 taken 616096 times.
✓ Branch 2 taken 767315 times.
✓ Branch 3 taken 2433987 times.
✓ Branch 4 taken 762689 times.
✓ Branch 5 taken 4626 times.
|
4584713 | join->where_cond && join->primary_tables == 1 && |
| 8029 | 767315 | join->group_list.empty() && | |
| 8030 |
7/8✓ Branch 0 taken 3817398 times.
✓ Branch 1 taken 11202 times.
✓ Branch 2 taken 762691 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 762561 times.
✓ Branch 5 taken 130 times.
✓ Branch 6 taken 761024 times.
✓ Branch 7 taken 3067578 times.
|
8408559 | !is_indexed_agg_distinct(join, &indexed_fields) && |
| 8031 |
2/2✓ Branch 0 taken 761024 times.
✓ Branch 1 taken 1537 times.
|
762561 | !join->select_distinct) { |
| 8032 |
1/2✓ Branch 0 taken 761024 times.
✗ Branch 1 not taken.
|
761024 | join->where_cond->walk(&Item::collect_item_field_processor, |
| 8033 | enum_walk::POSTFIX, (uchar *)&indexed_fields); | ||
| 8034 |
1/2✓ Branch 0 taken 761024 times.
✗ Branch 1 not taken.
|
761024 | Key_map possible_keys; |
| 8035 | 761024 | possible_keys.set_all(); | |
| 8036 | 761024 | join_tab->skip_scan_keys.clear_all(); | |
| 8037 |
7/12✓ Branch 0 taken 761024 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 761024 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1270773 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1269107 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2030131 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1270773 times.
✓ Branch 11 taken 759358 times.
|
2030131 | for (Item_field *cur_item : indexed_fields) { |
| 8038 |
3/4✓ Branch 0 taken 1270773 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1666 times.
✓ Branch 3 taken 1269107 times.
|
1270773 | if (cur_item->used_tables() != join_tab->table_ref->map()) return; |
| 8039 | 1269107 | possible_keys.intersect(cur_item->field->part_of_key); | |
| 8040 | } | ||
| 8041 | 759358 | join_tab->skip_scan_keys.merge(possible_keys); | |
| 8042 | 759358 | cause = "skip_scan"; | |
| 8043 | 759358 | return; | |
| 8044 | } | ||
| 8045 | |||
| 8046 |
2/2✓ Branch 0 taken 20167 times.
✓ Branch 1 taken 3047411 times.
|
3067578 | if (!join->group_list.empty()) { |
| 8047 | /* Collect all query fields referenced in the GROUP clause. */ | ||
| 8048 |
2/2✓ Branch 0 taken 46761 times.
✓ Branch 1 taken 20167 times.
|
66928 | for (cur_group = join->group_list.order; cur_group; |
| 8049 | 46761 | cur_group = cur_group->next) | |
| 8050 | 46761 | (*cur_group->item) | |
| 8051 |
1/2✓ Branch 0 taken 46761 times.
✗ Branch 1 not taken.
|
46761 | ->walk(&Item::collect_item_field_processor, enum_walk::POSTFIX, |
| 8052 | (uchar *)&indexed_fields); | ||
| 8053 | 20167 | cause = "group_by"; | |
| 8054 |
2/2✓ Branch 0 taken 8191 times.
✓ Branch 1 taken 3039220 times.
|
3047411 | } else if (join->select_distinct) { |
| 8055 | /* Collect all query fields referenced in the SELECT clause. */ | ||
| 8056 |
8/14✓ Branch 0 taken 8191 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8191 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8191 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 31799 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 31799 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 39990 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 31799 times.
✓ Branch 13 taken 8191 times.
|
39990 | for (Item *item : VisibleFields(*join->fields)) { |
| 8057 |
1/2✓ Branch 0 taken 31799 times.
✗ Branch 1 not taken.
|
31799 | item->walk(&Item::collect_item_field_processor, enum_walk::POSTFIX, |
| 8058 | (uchar *)&indexed_fields); | ||
| 8059 | } | ||
| 8060 | 8191 | cause = "distinct"; | |
| 8061 |
4/4✓ Branch 0 taken 395984 times.
✓ Branch 1 taken 2643236 times.
✓ Branch 2 taken 272 times.
✓ Branch 3 taken 3038948 times.
|
3435204 | } else if (join->tmp_table_param.sum_func_count && |
| 8062 |
3/4✓ Branch 0 taken 395984 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 272 times.
✓ Branch 3 taken 395712 times.
|
395984 | is_indexed_agg_distinct(join, &indexed_fields)) { |
| 8063 | /* | ||
| 8064 | SELECT list with AGGFN(distinct col). The query qualifies for | ||
| 8065 | loose index scan, and is_indexed_agg_distinct() has already | ||
| 8066 | collected all referenced fields into indexed_fields. | ||
| 8067 | */ | ||
| 8068 | 272 | join->streaming_aggregation = true; | |
| 8069 | 272 | cause = "indexed_distinct_aggregate"; | |
| 8070 | } else | ||
| 8071 | 3038948 | return; | |
| 8072 | |||
| 8073 |
3/4✓ Branch 0 taken 28630 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 229 times.
✓ Branch 3 taken 28401 times.
|
28630 | if (indexed_fields.empty()) return; |
| 8074 | |||
| 8075 | 28401 | Key_map possible_keys = join_tab->table()->keys_in_use_for_query; | |
| 8076 | 28401 | possible_keys.merge(join_tab->table()->keys_in_use_for_group_by); | |
| 8077 | |||
| 8078 | /* Intersect the keys of all group fields. */ | ||
| 8079 |
7/12✓ Branch 0 taken 28401 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28401 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37157 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 21686 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 50087 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 37157 times.
✓ Branch 11 taken 12930 times.
|
50087 | for (Item_field *cur_item : indexed_fields) { |
| 8080 |
3/4✓ Branch 0 taken 37157 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15471 times.
✓ Branch 3 taken 21686 times.
|
37157 | if (cur_item->used_tables() != join_tab->table_ref->map()) { |
| 8081 | /* | ||
| 8082 | Doing GROUP BY or DISTINCT on a field in another table so no | ||
| 8083 | index in this table is usable | ||
| 8084 | */ | ||
| 8085 | 15471 | return; | |
| 8086 | } else | ||
| 8087 | 21686 | possible_keys.intersect(cur_item->field->part_of_key); | |
| 8088 | } | ||
| 8089 | |||
| 8090 | /* | ||
| 8091 | At this point, possible_keys has key bits set only for usable | ||
| 8092 | indexes because indexed_fields is non-empty and if any of the | ||
| 8093 | fields belong to a different table the function would exit in the | ||
| 8094 | loop above. | ||
| 8095 | */ | ||
| 8096 | |||
| 8097 |
4/4✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 9526 times.
✓ Branch 2 taken 2484 times.
✓ Branch 3 taken 10446 times.
|
16334 | if (!possible_keys.is_clear_all() && |
| 8098 |
2/2✓ Branch 0 taken 2484 times.
✓ Branch 1 taken 920 times.
|
3404 | !possible_keys.is_subset(join_tab->const_keys)) { |
| 8099 |
1/2✓ Branch 0 taken 2484 times.
✗ Branch 1 not taken.
|
2484 | trace_indexes_added_group_distinct(&join->thd->opt_trace, join_tab, |
| 8100 | possible_keys, cause); | ||
| 8101 | 2484 | join_tab->const_keys.merge(possible_keys); | |
| 8102 | 2484 | join_tab->keys().merge(possible_keys); | |
| 8103 | } | ||
| 8104 | |||
| 8105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12930 times.
|
12930 | assert(join_tab->const_keys.is_subset(join_tab->keys())); |
| 8106 |
2/2✓ Branch 0 taken 12930 times.
✓ Branch 1 taken 3815674 times.
|
3828602 | } |
| 8107 | |||
| 8108 | /** | ||
| 8109 | Update keyuse array with all possible keys we can use to fetch rows. | ||
| 8110 | |||
| 8111 | @param thd session context | ||
| 8112 | @param[out] keyuse Put here ordered array of Key_use structures | ||
| 8113 | @param join_tab Array in table number order | ||
| 8114 | @param tables Number of tables in join | ||
| 8115 | @param cond WHERE condition (note that the function analyzes | ||
| 8116 | join_tab[i]->join_cond() too) | ||
| 8117 | @param normal_tables Tables not inner w.r.t some outer join (ones | ||
| 8118 | for which we can make ref access based the WHERE | ||
| 8119 | clause) | ||
| 8120 | @param query_block current SELECT | ||
| 8121 | @param[out] sargables Array of found sargable candidates | ||
| 8122 | |||
| 8123 | @returns false if success, true if error | ||
| 8124 | */ | ||
| 8125 | |||
| 8126 | 1309281 | static bool update_ref_and_keys(THD *thd, Key_use_array *keyuse, | |
| 8127 | JOIN_TAB *join_tab, uint tables, Item *cond, | ||
| 8128 | table_map normal_tables, | ||
| 8129 | Query_block *query_block, | ||
| 8130 | SARGABLE_PARAM **sargables) { | ||
| 8131 |
4/6✓ Branch 0 taken 1305192 times.
✓ Branch 1 taken 4089 times.
✓ Branch 2 taken 1305203 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1305203 times.
|
1309281 | assert(cond == nullptr || cond->is_bool_func()); |
| 8132 | uint and_level, i; | ||
| 8133 | Key_field *key_fields, *end, *field; | ||
| 8134 | size_t sz; | ||
| 8135 | 1309292 | uint m = max(query_block->max_equal_elems, 1U); | |
| 8136 | 1309289 | JOIN *const join = query_block->join; | |
| 8137 | /* | ||
| 8138 | We use the same piece of memory to store both Key_field | ||
| 8139 | and SARGABLE_PARAM structure. | ||
| 8140 | Key_field values are placed at the beginning this memory | ||
| 8141 | while SARGABLE_PARAM values are put at the end. | ||
| 8142 | All predicates that are used to fill arrays of Key_field | ||
| 8143 | and SARGABLE_PARAM structures have at most 2 arguments | ||
| 8144 | except BETWEEN predicates that have 3 arguments and | ||
| 8145 | IN predicates. | ||
| 8146 | This any predicate if it's not BETWEEN/IN can be used | ||
| 8147 | directly to fill at most 2 array elements, either of Key_field | ||
| 8148 | or SARGABLE_PARAM type. For a BETWEEN predicate 3 elements | ||
| 8149 | can be filled as this predicate is considered as | ||
| 8150 | saragable with respect to each of its argument. | ||
| 8151 | An IN predicate can require at most 1 element as currently | ||
| 8152 | it is considered as sargable only for its first argument. | ||
| 8153 | Multiple equality can add elements that are filled after | ||
| 8154 | substitution of field arguments by equal fields. There | ||
| 8155 | can be not more than query_block->max_equal_elems such | ||
| 8156 | substitutions. | ||
| 8157 | */ | ||
| 8158 | 1309289 | sz = max(sizeof(Key_field), sizeof(SARGABLE_PARAM)) * | |
| 8159 | 1309285 | (((query_block->cond_count + 1) * 2 + query_block->between_count) * m + | |
| 8160 | 1); | ||
| 8161 |
2/4✓ Branch 0 taken 1309292 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1309292 times.
|
1309285 | if (!(key_fields = (Key_field *)thd->alloc(sz))) |
| 8162 | ✗ | return true; /* purecov: inspected */ | |
| 8163 | 1309292 | and_level = 0; | |
| 8164 | 1309292 | field = end = key_fields; | |
| 8165 | 1309292 | *sargables = (SARGABLE_PARAM *)key_fields + | |
| 8166 | 1309292 | (sz - sizeof((*sargables)[0].field)) / sizeof(SARGABLE_PARAM); | |
| 8167 | /* set a barrier for the array of SARGABLE_PARAM */ | ||
| 8168 | 1309292 | (*sargables)[0].field = nullptr; | |
| 8169 | |||
| 8170 |
2/2✓ Branch 0 taken 1305206 times.
✓ Branch 1 taken 4086 times.
|
1309292 | if (cond) { |
| 8171 |
2/4✓ Branch 0 taken 1305206 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1305206 times.
|
1305206 | if (add_key_fields(thd, join, &end, &and_level, cond, normal_tables, |
| 8172 | sargables)) | ||
| 8173 | ✗ | return true; | |
| 8174 | |||
| 8175 | // The relevant secondary engines don't support antijoin, so don't enable | ||
| 8176 | // this optimization for them. | ||
| 8177 |
2/2✓ Branch 0 taken 1305086 times.
✓ Branch 1 taken 119 times.
|
1305206 | if (thd->secondary_engine_optimization() != |
| 8178 | Secondary_engine_optimization::SECONDARY) { | ||
| 8179 |
2/2✓ Branch 0 taken 4312307 times.
✓ Branch 1 taken 1305083 times.
|
5617390 | for (Key_field *fld = field; fld != end; fld++) { |
| 8180 | /* Mark that we can optimize LEFT JOIN */ | ||
| 8181 |
5/6✓ Branch 0 taken 4312304 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2633 times.
✓ Branch 3 taken 4309671 times.
✓ Branch 4 taken 361 times.
✓ Branch 5 taken 4311943 times.
|
4314940 | if (fld->val->type() == Item::NULL_ITEM && |
| 8182 |
2/2✓ Branch 0 taken 361 times.
✓ Branch 1 taken 2272 times.
|
2633 | !fld->item_field->field->is_nullable()) { |
| 8183 | /* | ||
| 8184 | Example: | ||
| 8185 | SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a WHERE t2.a IS NULL; | ||
| 8186 | this just wants rows of t1 where t1.a does not exist in t2. | ||
| 8187 | */ | ||
| 8188 | 361 | fld->item_field->field->table->reginfo.not_exists_optimize = true; | |
| 8189 | } | ||
| 8190 | } | ||
| 8191 | } | ||
| 8192 | } | ||
| 8193 | |||
| 8194 |
2/2✓ Branch 0 taken 3312263 times.
✓ Branch 1 taken 1309289 times.
|
4621552 | for (i = 0; i < tables; i++) { |
| 8195 | /* | ||
| 8196 | Block the creation of keys for inner tables of outer joins. | ||
| 8197 | Here only the outer joins that can not be converted to | ||
| 8198 | inner joins are left and all nests that can be eliminated | ||
| 8199 | are flattened. | ||
| 8200 | In the future when we introduce conditional accesses | ||
| 8201 | for inner tables in outer joins these keys will be taken | ||
| 8202 | into account as well. | ||
| 8203 | */ | ||
| 8204 |
2/2✓ Branch 0 taken 401940 times.
✓ Branch 1 taken 2910321 times.
|
3312263 | if (join_tab[i].join_cond()) { |
| 8205 |
2/4✓ Branch 0 taken 401943 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 401943 times.
|
401942 | if (add_key_fields(thd, join, &end, &and_level, join_tab[i].join_cond(), |
| 8206 | 401940 | join_tab[i].table_ref->map(), sargables)) | |
| 8207 | ✗ | return true; | |
| 8208 | } | ||
| 8209 | } | ||
| 8210 | |||
| 8211 | /* Process ON conditions for the nested joins */ | ||
| 8212 |
7/12✓ Branch 0 taken 1309295 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1309295 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3302623 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3302632 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4611920 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3302625 times.
✓ Branch 11 taken 1309295 times.
|
4611912 | for (TABLE_LIST *tl : query_block->top_join_list) { |
| 8213 |
3/4✓ Branch 0 taken 5959 times.
✓ Branch 1 taken 3296664 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3302623 times.
|
3308582 | if (tl->nested_join && |
| 8214 |
2/4✓ Branch 0 taken 5959 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5959 times.
|
5959 | add_key_fields_for_nj(thd, join, tl, &end, &and_level, sargables)) |
| 8215 | ✗ | return true; | |
| 8216 | } | ||
| 8217 | |||
| 8218 | /* Generate keys descriptions for derived tables */ | ||
| 8219 |
2/2✓ Branch 0 taken 3011 times.
✓ Branch 1 taken 1306284 times.
|
1309295 | if (query_block->materialized_derived_table_count) { |
| 8220 |
2/4✓ Branch 0 taken 3011 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3011 times.
|
3011 | if (join->generate_derived_keys()) return true; |
| 8221 | } | ||
| 8222 | /* fill keyuse with found key parts */ | ||
| 8223 |
2/2✓ Branch 0 taken 4827492 times.
✓ Branch 1 taken 1309298 times.
|
6136790 | for (; field != end; field++) { |
| 8224 |
2/4✓ Branch 0 taken 4827495 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4827495 times.
|
4827492 | if (add_key_part(keyuse, field)) return true; |
| 8225 | } | ||
| 8226 | |||
| 8227 |
2/2✓ Branch 0 taken 2212 times.
✓ Branch 1 taken 1307086 times.
|
1309298 | if (query_block->ftfunc_list->elements) { |
| 8228 |
2/4✓ Branch 0 taken 2212 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2212 times.
|
2212 | if (add_ft_keys(keyuse, cond, normal_tables, true)) return true; |
| 8229 | } | ||
| 8230 | |||
| 8231 | /* | ||
| 8232 | Sort the array of possible keys and remove the following key parts: | ||
| 8233 | - ref if there is a keypart which is a ref and a const. | ||
| 8234 | (e.g. if there is a key(a,b) and the clause is a=3 and b=7 and b=t2.d, | ||
| 8235 | then we skip the key part corresponding to b=t2.d) | ||
| 8236 | - keyparts without previous keyparts | ||
| 8237 | (e.g. if there is a key(a,b,c) but only b < 5 (or a=2 and c < 3) is | ||
| 8238 | used in the query, we drop the partial key parts from consideration). | ||
| 8239 | Special treatment for ft-keys. | ||
| 8240 | */ | ||
| 8241 |
3/4✓ Branch 0 taken 1309289 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 689968 times.
✓ Branch 3 taken 619321 times.
|
1309298 | if (!keyuse->empty()) { |
| 8242 | Key_use *save_pos, *use; | ||
| 8243 | |||
| 8244 |
1/2✓ Branch 0 taken 689970 times.
✗ Branch 1 not taken.
|
689968 | std::sort(keyuse->begin(), keyuse->begin() + keyuse->size(), sort_keyuse); |
| 8245 | |||
| 8246 | const Key_use key_end(nullptr, nullptr, 0, 0, 0, 0, 0, 0, false, nullptr, | ||
| 8247 | 689970 | 0); | |
| 8248 |
2/4✓ Branch 0 taken 689961 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 689961 times.
|
689968 | if (keyuse->push_back(key_end)) // added for easy testing |
| 8249 | ✗ | return true; | |
| 8250 | |||
| 8251 | 689961 | use = save_pos = keyuse->begin(); | |
| 8252 | 689963 | const Key_use *prev = &key_end; | |
| 8253 | 689963 | bool found_eq_constant = false; | |
| 8254 |
2/2✓ Branch 0 taken 7132012 times.
✓ Branch 1 taken 689943 times.
|
7821975 | for (i = 0; i < keyuse->size() - 1; i++, use++) { |
| 8255 | 7132012 | TABLE *const table = use->table_ref->table; | |
| 8256 |
5/6✓ Branch 0 taken 7132028 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1015013 times.
✓ Branch 3 taken 6117015 times.
✓ Branch 4 taken 1014805 times.
✓ Branch 5 taken 6117223 times.
|
8147025 | if (use->val->const_for_execution() && |
| 8257 |
2/2✓ Branch 0 taken 1014805 times.
✓ Branch 1 taken 208 times.
|
1015013 | use->optimize != KEY_OPTIMIZE_REF_OR_NULL) |
| 8258 | 1014805 | table->const_key_parts[use->key] |= use->keypart_map; | |
| 8259 |
2/2✓ Branch 0 taken 7129884 times.
✓ Branch 1 taken 2144 times.
|
7132028 | if (use->keypart != FT_KEYPART) { |
| 8260 |
4/4✓ Branch 0 taken 2475035 times.
✓ Branch 1 taken 4654849 times.
✓ Branch 2 taken 1298376 times.
✓ Branch 3 taken 1176659 times.
|
7129884 | if (use->key == prev->key && use->table_ref == prev->table_ref) { |
| 8261 |
2/2✓ Branch 0 taken 1297863 times.
✓ Branch 1 taken 513 times.
|
1298376 | if (prev->keypart + 1 < use->keypart || |
| 8262 |
4/4✓ Branch 0 taken 408495 times.
✓ Branch 1 taken 889368 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 408411 times.
|
1297863 | (prev->keypart == use->keypart && found_eq_constant)) |
| 8263 | 597 | continue; /* remove */ | |
| 8264 |
2/2✓ Branch 0 taken 1957984 times.
✓ Branch 1 taken 3873524 times.
|
5831508 | } else if (use->keypart != 0) // First found must be 0 |
| 8265 | 1957984 | continue; | |
| 8266 | } | ||
| 8267 | |||
| 8268 | /* | ||
| 8269 | Protect against self assignment. | ||
| 8270 | The compiler *may* generate a call to memcpy() to do the assignment, | ||
| 8271 | and that is undefined behaviour (memory overlap). | ||
| 8272 | */ | ||
| 8273 |
2/2✓ Branch 0 taken 2618726 times.
✓ Branch 1 taken 2554721 times.
|
5173447 | if (save_pos != use) *save_pos = *use; |
| 8274 | 5173447 | prev = use; | |
| 8275 |
1/2✓ Branch 0 taken 5173443 times.
✗ Branch 1 not taken.
|
5173447 | found_eq_constant = use->val->const_for_execution(); |
| 8276 | /* Save ptr to first use */ | ||
| 8277 |
2/2✓ Branch 0 taken 2591227 times.
✓ Branch 1 taken 2582216 times.
|
5173443 | if (!table->reginfo.join_tab->keyuse()) |
| 8278 | 2591227 | table->reginfo.join_tab->set_keyuse(save_pos); | |
| 8279 | 5173442 | table->reginfo.join_tab->checked_keys.set_bit(use->key); | |
| 8280 | 5173431 | save_pos++; | |
| 8281 | } | ||
| 8282 | 689943 | i = (uint)(save_pos - keyuse->begin()); | |
| 8283 | 689970 | keyuse->at(i) = key_end; | |
| 8284 | 689969 | keyuse->chop(i); | |
| 8285 | } | ||
| 8286 |
1/2✓ Branch 0 taken 1309289 times.
✗ Branch 1 not taken.
|
1309290 | print_keyuse_array(thd, &thd->opt_trace, keyuse); |
| 8287 | /* | ||
| 8288 | Number of functions here call val_x() methods, which might throw an error. | ||
| 8289 | Catch those errors here. | ||
| 8290 | */ | ||
| 8291 |
1/2✓ Branch 0 taken 1309294 times.
✗ Branch 1 not taken.
|
1309289 | return thd->is_error(); |
| 8292 | } | ||
| 8293 | |||
| 8294 | /** | ||
| 8295 | Create a keyuse array for a table with a primary key. | ||
| 8296 | To be used when creating a materialized temporary table. | ||
| 8297 | |||
| 8298 | @param thd THD pointer, for memory allocation | ||
| 8299 | @param keyparts Number of key parts in the primary key | ||
| 8300 | @param fields fields | ||
| 8301 | @param outer_exprs List of items used for key lookup | ||
| 8302 | |||
| 8303 | @return Pointer to created keyuse array, or NULL if error | ||
| 8304 | */ | ||
| 8305 | 934 | Key_use_array *create_keyuse_for_table( | |
| 8306 | THD *thd, uint keyparts, Item_field **fields, | ||
| 8307 | const mem_root_deque<Item *> &outer_exprs) { | ||
| 8308 |
1/2✓ Branch 0 taken 934 times.
✗ Branch 1 not taken.
|
934 | void *mem = thd->alloc(sizeof(Key_use_array)); |
| 8309 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 934 times.
|
934 | if (!mem) return nullptr; |
| 8310 |
1/2✓ Branch 0 taken 934 times.
✗ Branch 1 not taken.
|
934 | Key_use_array *keyuses = new (mem) Key_use_array(thd->mem_root); |
| 8311 | |||
| 8312 |
1/2✓ Branch 0 taken 934 times.
✗ Branch 1 not taken.
|
934 | auto outer_expr_it = outer_exprs.begin(); |
| 8313 | |||
| 8314 |
2/2✓ Branch 0 taken 945 times.
✓ Branch 1 taken 934 times.
|
1879 | for (uint keypartno = 0; keypartno < keyparts; keypartno++) { |
| 8315 |
2/4✓ Branch 0 taken 945 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 945 times.
✗ Branch 3 not taken.
|
945 | Item *const item = *outer_expr_it++; |
| 8316 | 945 | Key_field key_field(fields[keypartno], item, 0, 0, true, | |
| 8317 | // null_rejecting must be true for field items only, | ||
| 8318 | // add_not_null_conds() is incapable of handling | ||
| 8319 | // other item types. | ||
| 8320 |
1/2✓ Branch 0 taken 945 times.
✗ Branch 1 not taken.
|
945 | (item->type() == Item::FIELD_ITEM), nullptr, UINT_MAX); |
| 8321 |
2/4✓ Branch 0 taken 945 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 945 times.
|
945 | if (add_key_part(keyuses, &key_field)) return nullptr; |
| 8322 | } | ||
| 8323 | 934 | const Key_use key_end(nullptr, nullptr, 0, 0, 0, 0, 0, 0, false, nullptr, 0); | |
| 8324 |
2/4✓ Branch 0 taken 934 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 934 times.
|
934 | if (keyuses->push_back(key_end)) // added for easy testing |
| 8325 | ✗ | return nullptr; | |
| 8326 | |||
| 8327 | 934 | return keyuses; | |
| 8328 | } | ||
| 8329 | |||
| 8330 | /** | ||
| 8331 | Move const tables first in the position array. | ||
| 8332 | |||
| 8333 | Increment the number of const tables and set same basic properties for the | ||
| 8334 | const table. | ||
| 8335 | A const table looked up by a key has type JT_CONST. | ||
| 8336 | A const table with a single row has type JT_SYSTEM. | ||
| 8337 | |||
| 8338 | @param tab Table that is designated as a const table | ||
| 8339 | @param key The key definition to use for this table (NULL if table scan) | ||
| 8340 | */ | ||
| 8341 | |||
| 8342 | 101053 | void JOIN::mark_const_table(JOIN_TAB *tab, Key_use *key) { | |
| 8343 | 101053 | POSITION *const position = positions + const_tables; | |
| 8344 | 101053 | position->table = tab; | |
| 8345 | 101053 | position->key = key; | |
| 8346 | 101053 | position->rows_fetched = 1.0; // This is a const table | |
| 8347 | 101053 | position->filter_effect = 1.0; | |
| 8348 | 101053 | position->prefix_rowcount = 1.0; | |
| 8349 | 101053 | position->read_cost = 0.0; | |
| 8350 | 101053 | position->ref_depend_map = 0; | |
| 8351 | 101053 | position->loosescan_key = MAX_KEY; // Not a LooseScan | |
| 8352 | 101053 | position->sj_strategy = SJ_OPT_NONE; | |
| 8353 | 101053 | positions->use_join_buffer = false; | |
| 8354 | |||
| 8355 | // Move the const table as far down as possible in best_ref | ||
| 8356 | 101053 | JOIN_TAB **pos = best_ref + const_tables + 1; | |
| 8357 |
2/2✓ Branch 0 taken 699 times.
✓ Branch 1 taken 101053 times.
|
101752 | for (JOIN_TAB *next = best_ref[const_tables]; next != tab; pos++) { |
| 8358 | 699 | JOIN_TAB *const tmp = pos[0]; | |
| 8359 | 699 | pos[0] = next; | |
| 8360 | 699 | next = tmp; | |
| 8361 | } | ||
| 8362 | 101053 | best_ref[const_tables] = tab; | |
| 8363 | |||
| 8364 |
2/2✓ Branch 0 taken 85410 times.
✓ Branch 1 taken 15643 times.
|
101053 | tab->set_type(key ? JT_CONST : JT_SYSTEM); |
| 8365 | |||
| 8366 | 101055 | const_table_map |= tab->table_ref->map(); | |
| 8367 | |||
| 8368 | 101055 | const_tables++; | |
| 8369 | 101055 | } | |
| 8370 | |||
| 8371 | 150663 | void JOIN::make_outerjoin_info() { | |
| 8372 |
1/2✓ Branch 0 taken 150679 times.
✗ Branch 1 not taken.
|
150663 | DBUG_TRACE; |
| 8373 | |||
| 8374 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 150679 times.
|
150679 | assert(query_block->outer_join); |
| 8375 |
4/6✓ Branch 0 taken 150671 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 150671 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 150672 times.
✗ Branch 5 not taken.
|
150679 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 8376 | |||
| 8377 |
1/2✓ Branch 0 taken 150680 times.
✗ Branch 1 not taken.
|
150680 | query_block->reset_nj_counters(); |
| 8378 | |||
| 8379 |
2/2✓ Branch 0 taken 1238879 times.
✓ Branch 1 taken 150703 times.
|
1389582 | for (uint i = const_tables; i < tables; ++i) { |
| 8380 | 1238879 | JOIN_TAB *const tab = best_ref[i]; | |
| 8381 | 1238879 | TABLE *const table = tab->table(); | |
| 8382 |
2/2✓ Branch 0 taken 270366 times.
✓ Branch 1 taken 968539 times.
|
1238905 | if (!table) continue; |
| 8383 | |||
| 8384 | 968539 | TABLE_LIST *const tbl = tab->table_ref; | |
| 8385 | /* | ||
| 8386 | If 'tbl' is inside a SJ/AJ nest served by materialization, we must | ||
| 8387 | limit setting first_inner, last_inner and first_upper for join nests | ||
| 8388 | inside the materialized table. Indeed it is the SJ-tmp table, and not | ||
| 8389 | 'tbl', which interacts with the nests outer to the SJ/AJ nest. | ||
| 8390 | */ | ||
| 8391 | const bool sj_mat_inner = | ||
| 8392 |
1/2✓ Branch 0 taken 968548 times.
✗ Branch 1 not taken.
|
968539 | sj_is_materialize_strategy(tab->get_sj_strategy()); |
| 8393 | |||
| 8394 |
2/2✓ Branch 0 taken 401749 times.
✓ Branch 1 taken 566800 times.
|
968549 | if (tbl->outer_join) { |
| 8395 | /* | ||
| 8396 | Table tab is the only one inner table for outer join. | ||
| 8397 | (Like table t4 for the table reference t3 LEFT JOIN t4 ON t3.a=t4.a | ||
| 8398 | is in the query above.) | ||
| 8399 | */ | ||
| 8400 | 401749 | tab->set_last_inner(i); | |
| 8401 | 401750 | tab->set_first_inner(i); | |
| 8402 |
1/2✓ Branch 0 taken 401749 times.
✗ Branch 1 not taken.
|
401748 | tab->init_join_cond_ref(tbl); |
| 8403 | 401749 | tab->cond_equal = tbl->cond_equal; | |
| 8404 | /* | ||
| 8405 | If this outer join nest is embedded in another join nest, | ||
| 8406 | link the join-tabs: | ||
| 8407 | */ | ||
| 8408 | 401749 | TABLE_LIST *const outer_join_nest = tbl->outer_join_nest(); | |
| 8409 |
2/2✓ Branch 0 taken 425 times.
✓ Branch 1 taken 401322 times.
|
401747 | if (outer_join_nest) { |
| 8410 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 425 times.
|
425 | assert(outer_join_nest->nested_join->first_nested != NO_PLAN_IDX); |
| 8411 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 425 times.
✓ Branch 2 taken 425 times.
✗ Branch 3 not taken.
|
425 | if (!sj_mat_inner || |
| 8412 | ✗ | (tab->emb_sj_nest->sj_inner_tables & | |
| 8413 | ✗ | best_ref[outer_join_nest->nested_join->first_nested] | |
| 8414 | ✗ | ->table_ref->map())) | |
| 8415 | 425 | tab->set_first_upper(outer_join_nest->nested_join->first_nested); | |
| 8416 | } | ||
| 8417 | } | ||
| 8418 |
2/2✓ Branch 0 taken 12503 times.
✓ Branch 1 taken 964818 times.
|
977321 | for (TABLE_LIST *embedding = tbl->embedding; embedding; |
| 8419 | 8785 | embedding = embedding->embedding) { | |
| 8420 | // When reaching the outer tables of the materialized temporary table, | ||
| 8421 | // the decoration for this table is complete. | ||
| 8422 |
4/4✓ Branch 0 taken 1686 times.
✓ Branch 1 taken 10817 times.
✓ Branch 2 taken 1684 times.
✓ Branch 3 taken 2 times.
|
12503 | if (sj_mat_inner && embedding == tab->emb_sj_nest) break; |
| 8423 | // Ignore join nests that are not outer join nests: | ||
| 8424 |
2/2✓ Branch 0 taken 6935 times.
✓ Branch 1 taken 3884 times.
|
10819 | if (!embedding->join_cond_optim()) continue; |
| 8425 | 3884 | NESTED_JOIN *const nested_join = embedding->nested_join; | |
| 8426 |
2/2✓ Branch 0 taken 1850 times.
✓ Branch 1 taken 2034 times.
|
3884 | if (!nested_join->nj_counter) { |
| 8427 | /* | ||
| 8428 | Table tab is the first inner table for nested_join. | ||
| 8429 | Save reference to it in the nested join structure. | ||
| 8430 | */ | ||
| 8431 | 1850 | nested_join->first_nested = i; | |
| 8432 | // The table's condition is set to point to the join nest's condition | ||
| 8433 |
1/2✓ Branch 0 taken 1850 times.
✗ Branch 1 not taken.
|
1850 | tab->init_join_cond_ref(embedding); |
| 8434 | 1850 | tab->cond_equal = tbl->cond_equal; | |
| 8435 | |||
| 8436 | 1850 | TABLE_LIST *const outer_join_nest = embedding->outer_join_nest(); | |
| 8437 |
2/2✓ Branch 0 taken 132 times.
✓ Branch 1 taken 1718 times.
|
1850 | if (outer_join_nest) { |
| 8438 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
|
132 | assert(outer_join_nest->nested_join->first_nested != NO_PLAN_IDX); |
| 8439 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
✓ Branch 2 taken 132 times.
✗ Branch 3 not taken.
|
132 | if (!sj_mat_inner || |
| 8440 | ✗ | (tab->emb_sj_nest->sj_inner_tables & | |
| 8441 | ✗ | best_ref[outer_join_nest->nested_join->first_nested] | |
| 8442 | ✗ | ->table_ref->map())) | |
| 8443 | 132 | tab->set_first_upper(outer_join_nest->nested_join->first_nested); | |
| 8444 | } | ||
| 8445 | } | ||
| 8446 |
2/2✓ Branch 0 taken 3327 times.
✓ Branch 1 taken 557 times.
|
3884 | if (tab->first_inner() == NO_PLAN_IDX) |
| 8447 | 3327 | tab->set_first_inner(nested_join->first_nested); | |
| 8448 | /* | ||
| 8449 | If including the sj-mat tmp table, this also implicitly | ||
| 8450 | includes the inner tables of the sj-nest. | ||
| 8451 | */ | ||
| 8452 | 3884 | nested_join->nj_counter += | |
| 8453 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 3856 times.
|
3884 | tab->sj_mat_exec() ? tab->sj_mat_exec()->table_count : 1; |
| 8454 |
2/2✓ Branch 0 taken 2034 times.
✓ Branch 1 taken 1850 times.
|
3884 | if (nested_join->nj_counter < nested_join->nj_total) break; |
| 8455 | // Table tab is the last inner table for nested join. | ||
| 8456 | 1850 | best_ref[nested_join->first_nested]->set_last_inner(i); | |
| 8457 | } | ||
| 8458 | } | ||
| 8459 | 150703 | } | |
| 8460 | |||
| 8461 | /** | ||
| 8462 | Build a condition guarded by match variables for embedded outer joins. | ||
| 8463 | When generating a condition for a table as part of an outer join condition | ||
| 8464 | or the WHERE condition, the table in question may also be part of an | ||
| 8465 | embedded outer join. In such cases, the condition must be guarded by | ||
| 8466 | the match variable for this embedded outer join. Such embedded outer joins | ||
| 8467 | may also be recursively embedded in other joins. | ||
| 8468 | |||
| 8469 | The function recursively adds guards for a condition ascending from tab | ||
| 8470 | to root_tab, which is the first inner table of an outer join, | ||
| 8471 | or NULL if the condition being handled is the WHERE clause. | ||
| 8472 | |||
| 8473 | @param join the current join | ||
| 8474 | @param idx index of the first inner table for the inner-most outer join | ||
| 8475 | @param cond the predicate to be guarded (must be set) | ||
| 8476 | @param root_idx index of the inner table to stop at | ||
| 8477 | (is NO_PLAN_IDX if this is the WHERE clause) | ||
| 8478 | |||
| 8479 | @return | ||
| 8480 | - pointer to the guarded predicate, if success | ||
| 8481 | - NULL if error | ||
| 8482 | */ | ||
| 8483 | |||
| 8484 | 2762483 | static Item *add_found_match_trig_cond(JOIN *join, plan_idx idx, Item *cond, | |
| 8485 | plan_idx root_idx) { | ||
| 8486 |
4/6✓ Branch 0 taken 2762486 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2762487 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2762483 times.
✓ Branch 5 taken 4 times.
|
2762483 | ASSERT_BEST_REF_IN_JOIN_ORDER(join); |
| 8487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2762485 times.
|
2762480 | assert(cond->is_bool_func()); |
| 8488 | |||
| 8489 |
2/2✓ Branch 0 taken 3902 times.
✓ Branch 1 taken 2762473 times.
|
2766387 | for (; idx != root_idx; idx = join->best_ref[idx]->first_upper()) { |
| 8490 |
2/4✓ Branch 0 taken 3902 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3902 times.
|
7804 | if (!(cond = new Item_func_trig_cond(cond, nullptr, join, idx, |
| 8491 |
1/2✓ Branch 0 taken 3902 times.
✗ Branch 1 not taken.
|
7804 | Item_func_trig_cond::FOUND_MATCH))) |
| 8492 | ✗ | return nullptr; | |
| 8493 | |||
| 8494 | 3902 | cond->quick_fix_field(); | |
| 8495 | 3902 | cond->update_used_tables(); | |
| 8496 | } | ||
| 8497 | |||
| 8498 | 2762473 | return cond; | |
| 8499 | } | ||
| 8500 | |||
| 8501 | /** | ||
| 8502 | Helper for JOIN::attach_join_conditions(). | ||
| 8503 | Attaches bits of 'join_cond' to each table in the range [first_inner, | ||
| 8504 | last_tab], with proper guards. | ||
| 8505 | If 'sj_mat_cond' is true, we do not see first_inner (and tables on the same | ||
| 8506 | level of it) as inner to anything, as they're at the top from the POV of | ||
| 8507 | the materialization of the tmp table. So, if the SJ-mat nest is A LJ B, | ||
| 8508 | A will get a part of condition without any guard; B will get another part | ||
| 8509 | with a guard on A->found_match. It's like pushing a WHERE. | ||
| 8510 | */ | ||
| 8511 | 403560 | bool JOIN::attach_join_condition_to_nest(plan_idx first_inner, | |
| 8512 | plan_idx last_tab, Item *join_cond, | ||
| 8513 | bool is_sj_mat_cond) { | ||
| 8514 | /* | ||
| 8515 | Add the constant part of the join condition to the first inner table | ||
| 8516 | of the outer join. | ||
| 8517 | */ | ||
| 8518 | Item *cond = | ||
| 8519 | 403560 | make_cond_for_table(thd, join_cond, const_table_map, table_map(0), false); | |
| 8520 |
2/2✓ Branch 0 taken 365 times.
✓ Branch 1 taken 403194 times.
|
403559 | if (cond) { |
| 8521 |
2/2✓ Branch 0 taken 355 times.
✓ Branch 1 taken 10 times.
|
365 | if (!is_sj_mat_cond) { |
| 8522 |
1/2✓ Branch 0 taken 355 times.
✗ Branch 1 not taken.
|
710 | cond = new Item_func_trig_cond(cond, nullptr, this, first_inner, |
| 8523 |
1/2✓ Branch 0 taken 355 times.
✗ Branch 1 not taken.
|
710 | Item_func_trig_cond::IS_NOT_NULL_COMPL); |
| 8524 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 355 times.
|
355 | if (!cond) return true; |
| 8525 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 355 times.
|
355 | if (cond->fix_fields(thd, nullptr)) return true; |
| 8526 | } | ||
| 8527 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 355 times.
|
365 | if (best_ref[first_inner]->and_with_condition(cond)) return true; |
| 8528 | } | ||
| 8529 | /* | ||
| 8530 | Split the non-constant part of the join condition into parts that | ||
| 8531 | can be attached to the inner tables of the outer join. | ||
| 8532 | */ | ||
| 8533 |
2/2✓ Branch 0 taken 405700 times.
✓ Branch 1 taken 403560 times.
|
809260 | for (plan_idx i = first_inner; i <= last_tab; ++i) { |
| 8534 | 405700 | table_map prefix_tables = best_ref[i]->prefix_tables(); | |
| 8535 | 405711 | table_map added_tables = best_ref[i]->added_tables(); | |
| 8536 | |||
| 8537 | /* | ||
| 8538 | When handling the first inner table of an outer join, we may also | ||
| 8539 | reference all tables ahead of this table: | ||
| 8540 | */ | ||
| 8541 |
2/2✓ Branch 0 taken 403560 times.
✓ Branch 1 taken 2156 times.
|
405716 | if (i == first_inner) added_tables = prefix_tables; |
| 8542 | /* | ||
| 8543 | We need RAND_TABLE_BIT on the last inner table, in case there is a | ||
| 8544 | non-deterministic function in the join condition. | ||
| 8545 | (RAND_TABLE_BIT is set for the last table of the join plan, | ||
| 8546 | but this is not sufficient for join conditions, which may have a | ||
| 8547 | last inner table that is ahead of the last table of the join plan). | ||
| 8548 | */ | ||
| 8549 |
2/2✓ Branch 0 taken 403559 times.
✓ Branch 1 taken 2157 times.
|
405716 | if (i == last_tab) { |
| 8550 | 403559 | prefix_tables |= RAND_TABLE_BIT; | |
| 8551 | 403559 | added_tables |= RAND_TABLE_BIT; | |
| 8552 | } | ||
| 8553 | cond = | ||
| 8554 | 405716 | make_cond_for_table(thd, join_cond, prefix_tables, added_tables, false); | |
| 8555 |
2/2✓ Branch 0 taken 1373 times.
✓ Branch 1 taken 404339 times.
|
405712 | if (cond == nullptr) continue; |
| 8556 | /* | ||
| 8557 | If the table is part of an outer join that is embedded in the | ||
| 8558 | outer join currently being processed, wrap the condition in | ||
| 8559 | triggered conditions for match variables of such embedded outer joins. | ||
| 8560 | */ | ||
| 8561 |
3/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 404330 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 404342 times.
|
808679 | if (!(cond = add_found_match_trig_cond( |
| 8562 | 404339 | this, best_ref[i]->first_inner(), cond, | |
| 8563 | is_sj_mat_cond ? NO_PLAN_IDX : first_inner))) | ||
| 8564 | ✗ | return true; | |
| 8565 | |||
| 8566 |
2/2✓ Branch 0 taken 404333 times.
✓ Branch 1 taken 9 times.
|
404342 | if (!is_sj_mat_cond) { |
| 8567 | // Add the guard turning the predicate off for the null-complemented row. | ||
| 8568 |
1/2✓ Branch 0 taken 404328 times.
✗ Branch 1 not taken.
|
808660 | cond = new Item_func_trig_cond(cond, nullptr, this, first_inner, |
| 8569 |
1/2✓ Branch 0 taken 404332 times.
✗ Branch 1 not taken.
|
808661 | Item_func_trig_cond::IS_NOT_NULL_COMPL); |
| 8570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 404332 times.
|
404332 | if (!cond) return true; |
| 8571 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 404335 times.
|
404332 | if (cond->fix_fields(thd, nullptr)) return true; |
| 8572 | } | ||
| 8573 | // Add the generated condition to the existing table condition | ||
| 8574 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 404338 times.
|
404344 | if (best_ref[i]->and_with_condition(cond)) return true; |
| 8575 | } | ||
| 8576 | 403560 | return false; | |
| 8577 | } | ||
| 8578 | |||
| 8579 | /** | ||
| 8580 | Attach outer join conditions to generated table conditions in an optimal way. | ||
| 8581 | |||
| 8582 | @param last_tab - Last table that has been added to the current plan. | ||
| 8583 | Pre-condition: If this is the last inner table of an outer | ||
| 8584 | join operation, a join condition is attached to the first | ||
| 8585 | inner table of that outer join operation. | ||
| 8586 | |||
| 8587 | @return false if success, true if error. | ||
| 8588 | |||
| 8589 | Outer join conditions are attached to individual tables, but we can analyze | ||
| 8590 | those conditions only when reaching the last inner table of an outer join | ||
| 8591 | operation. Notice also that a table can be last within several outer join | ||
| 8592 | nests, hence the outer for() loop of this function. | ||
| 8593 | |||
| 8594 | Example: | ||
| 8595 | SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) ON t1.a=t2.a | ||
| 8596 | |||
| 8597 | Table t3 is last both in the join nest (t2 - t3) and in (t1 - (t2 - t3)) | ||
| 8598 | Thus, join conditions for both join nests will be evaluated when reaching | ||
| 8599 | this table. | ||
| 8600 | |||
| 8601 | For each outer join operation processed, the join condition is split | ||
| 8602 | optimally over the inner tables of the outer join. The split-out conditions | ||
| 8603 | are later referred to as table conditions (but note that several table | ||
| 8604 | conditions stemming from different join operations may be combined into | ||
| 8605 | a composite table condition). | ||
| 8606 | |||
| 8607 | Example: | ||
| 8608 | Consider the above query once more. | ||
| 8609 | The predicate t1.a=t2.a can be evaluated when rows from t1 and t2 are ready, | ||
| 8610 | ie at table t2. The predicate t2.a=t3.a can be evaluated at table t3. | ||
| 8611 | |||
| 8612 | Each non-constant split-out table condition is guarded by a match variable | ||
| 8613 | that enables it only when a matching row is found for all the embedded | ||
| 8614 | outer join operations. | ||
| 8615 | |||
| 8616 | Each split-out table condition is guarded by a variable that turns the | ||
| 8617 | condition off just before a null-complemented row for the outer join | ||
| 8618 | operation is formed. Thus, the join condition will not be checked for | ||
| 8619 | the null-complemented row. | ||
| 8620 | */ | ||
| 8621 | |||
| 8622 | 3826452 | bool JOIN::attach_join_conditions(plan_idx last_tab) { | |
| 8623 |
1/2✓ Branch 0 taken 3826471 times.
✗ Branch 1 not taken.
|
3826452 | DBUG_TRACE; |
| 8624 |
4/6✓ Branch 0 taken 3826472 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3826456 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 3826468 times.
✗ Branch 5 not taken.
|
3826471 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 8625 | |||
| 8626 | 3826467 | JOIN_TAB *lt = best_ref[last_tab]; | |
| 8627 | |||
| 8628 | 3826467 | for (plan_idx first_inner = lt->first_inner(); | |
| 8629 |
6/6✓ Branch 0 taken 405530 times.
✓ Branch 1 taken 3824480 times.
✓ Branch 2 taken 403550 times.
✓ Branch 3 taken 1980 times.
✓ Branch 4 taken 403550 times.
✓ Branch 5 taken 3826460 times.
|
4635540 | first_inner != NO_PLAN_IDX && |
| 8630 | 405530 | best_ref[first_inner]->last_inner() == last_tab; | |
| 8631 | 403544 | first_inner = best_ref[first_inner]->first_upper()) { | |
| 8632 | /* | ||
| 8633 | Table last_tab is the last inner table of an outer join, locate | ||
| 8634 | the corresponding join condition from the first inner table of the | ||
| 8635 | same outer join: | ||
| 8636 | */ | ||
| 8637 | 403550 | Item *const join_cond = best_ref[first_inner]->join_cond(); | |
| 8638 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 403549 times.
|
403549 | assert(join_cond); |
| 8639 |
2/4✓ Branch 0 taken 403544 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 403544 times.
|
403549 | if (attach_join_condition_to_nest(first_inner, last_tab, join_cond, false)) |
| 8640 | ✗ | return true; | |
| 8641 | } | ||
| 8642 |
3/4✓ Branch 0 taken 3826469 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2374 times.
✓ Branch 3 taken 3824096 times.
|
3826460 | if (sj_is_materialize_strategy(lt->get_sj_strategy())) { |
| 8643 | 2374 | plan_idx mat_tbl = NO_PLAN_IDX; | |
| 8644 | /* | ||
| 8645 | The SJ nest's condition contains both the SJ equality condition and the | ||
| 8646 | WHERE of the replaced subquery. This WHERE must be pushed to SJ-inner | ||
| 8647 | tables for evaluation during materialization! | ||
| 8648 | */ | ||
| 8649 | 2374 | Semijoin_mat_exec *sjm = nullptr; | |
| 8650 | 2374 | for (plan_idx j = last_tab;; j--) { | |
| 8651 | 17812 | sjm = best_ref[j]->sj_mat_exec(); | |
| 8652 |
4/4✓ Branch 0 taken 2384 times.
✓ Branch 1 taken 15428 times.
✓ Branch 2 taken 2374 times.
✓ Branch 3 taken 10 times.
|
17812 | if (sjm && sjm->sj_nest == lt->emb_sj_nest) { |
| 8653 | // 'j' is the sj-mat tmp table | ||
| 8654 | 2374 | mat_tbl = j; | |
| 8655 | 2374 | break; | |
| 8656 | } | ||
| 8657 | } | ||
| 8658 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2374 times.
|
2374 | assert(sjm); |
| 8659 |
2/2✓ Branch 0 taken 934 times.
✓ Branch 1 taken 1440 times.
|
2374 | if (sjm->inner_table_index + sjm->table_count - 1 == (uint)last_tab) { |
| 8660 | // we're at last table of sjmat nest | ||
| 8661 | 934 | auto join_cond = best_ref[mat_tbl]->join_cond(); | |
| 8662 |
5/8✓ Branch 0 taken 10 times.
✓ Branch 1 taken 924 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 934 times.
|
934 | if (join_cond && attach_join_condition_to_nest(sjm->inner_table_index, |
| 8663 | last_tab, join_cond, true)) | ||
| 8664 | ✗ | return true; | |
| 8665 | } | ||
| 8666 | } | ||
| 8667 | |||
| 8668 | /* | ||
| 8669 | See if 'last_tab' is the first inner of an antijoin nest, | ||
| 8670 | then add a IS NULL condition on it. | ||
| 8671 | By attaching the condition to the first inner table, we know that if | ||
| 8672 | it is not satisfied we can just jump back to the table right before | ||
| 8673 | it. | ||
| 8674 | */ | ||
| 8675 |
4/4✓ Branch 0 taken 224 times.
✓ Branch 1 taken 13592 times.
✓ Branch 2 taken 197 times.
✓ Branch 3 taken 27 times.
|
14040 | if (lt->table_ref->embedding && lt->table_ref->embedding->is_aj_nest() && |
| 8676 |
5/6✓ Branch 0 taken 13816 times.
✓ Branch 1 taken 3812654 times.
✓ Branch 2 taken 188 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 188 times.
✓ Branch 5 taken 3826272 times.
|
3840500 | last_tab == lt->first_inner() && |
| 8677 | /* | ||
| 8678 | Exception: in A AJ (B LJ C) where C is a single table: there is no | ||
| 8679 | join nest for C as it's single; C->embedding is thus the AJ nest; but | ||
| 8680 | C->first_inner() is C (as it's the first inner of the LJ operation). | ||
| 8681 | In that case it's not the first inner table of the AJ. | ||
| 8682 | Catch this case: | ||
| 8683 | */ | ||
| 8684 | 198 | !lt->table_ref->join_cond()) { | |
| 8685 |
1/2✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
|
376 | Item *cond = new Item_func_false(); |
| 8686 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 188 times.
|
188 | if (!cond) return true; |
| 8687 | // This is a signal for JOIN::create_access_paths | ||
| 8688 | 188 | cond->item_name.set(antijoin_null_cond); | |
| 8689 | /* | ||
| 8690 | For A AJ B ON COND, we need an IS NULL condition which | ||
| 8691 | is tested on the result rows of A LEFT JOIN B ON COND. | ||
| 8692 | It must be tested only after the "match status" of a row of B has been | ||
| 8693 | decided, so is wrapped in a condition triggered by B->found_match. | ||
| 8694 | To have it test IS NULL, it's wrapped in a triggered condition which is | ||
| 8695 | false if B is not NULL-complemented. | ||
| 8696 | We needn't wrap this condition with triggers from upper nests, hence the | ||
| 8697 | last argument of the call below. | ||
| 8698 | */ | ||
| 8699 |
1/2✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
|
188 | cond = add_found_match_trig_cond(this, last_tab, cond, lt->first_upper()); |
| 8700 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 188 times.
|
188 | if (!cond) return true; |
| 8701 |
1/2✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
|
376 | cond = new Item_func_trig_cond(cond, nullptr, this, last_tab, |
| 8702 |
1/2✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
|
376 | Item_func_trig_cond::IS_NOT_NULL_COMPL); |
| 8703 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 188 times.
|
188 | if (!cond) return true; |
| 8704 |
2/4✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 188 times.
|
188 | if (cond->fix_fields(thd, nullptr)) return true; |
| 8705 |
2/4✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 188 times.
|
188 | if (lt->and_with_condition(cond)) return true; |
| 8706 | 188 | lt->table()->reginfo.not_exists_optimize = true; | |
| 8707 | |||
| 8708 | // The relevant secondary engines don't support antijoin, so don't enable | ||
| 8709 | // this optimization for them. | ||
| 8710 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 177 times.
|
188 | assert(thd->secondary_engine_optimization() != |
| 8711 | Secondary_engine_optimization::SECONDARY); | ||
| 8712 | } | ||
| 8713 | |||
| 8714 | 3826449 | return false; | |
| 8715 | 3826449 | } | |
| 8716 | |||
| 8717 | /***************************************************************************** | ||
| 8718 | Remove calculation with tables that aren't yet read. Remove also tests | ||
| 8719 | against fields that are read through key where the table is not a | ||
| 8720 | outer join table. | ||
| 8721 | We can't remove tests that are made against columns which are stored | ||
| 8722 | in sorted order. | ||
| 8723 | *****************************************************************************/ | ||
| 8724 | |||
| 8725 | 3420475 | static Item *part_of_refkey(TABLE *table, TABLE_REF *ref, const Field *field) { | |
| 8726 | 3420475 | uint ref_parts = ref->key_parts; | |
| 8727 |
2/2✓ Branch 0 taken 2750610 times.
✓ Branch 1 taken 669865 times.
|
3420475 | if (ref_parts) { |
| 8728 |
2/2✓ Branch 0 taken 69 times.
✓ Branch 1 taken 2750533 times.
|
2750610 | if (ref->has_guarded_conds()) return nullptr; |
| 8729 | |||
| 8730 | 2750533 | const KEY_PART_INFO *key_part = table->key_info[ref->key].key_part; | |
| 8731 | |||
| 8732 |
2/2✓ Branch 0 taken 3511008 times.
✓ Branch 1 taken 117731 times.
|
3628739 | for (uint part = 0; part < ref_parts; part++, key_part++) |
| 8733 |
4/4✓ Branch 0 taken 2643640 times.
✓ Branch 1 taken 867373 times.
✓ Branch 2 taken 2632807 times.
✓ Branch 3 taken 878206 times.
|
6154648 | if (field->eq(key_part->field) && |
| 8734 |
2/2✓ Branch 0 taken 2632806 times.
✓ Branch 1 taken 10834 times.
|
2643640 | !(key_part->key_part_flag & HA_PART_KEY_SEG)) |
| 8735 | 2632807 | return ref->items[part]; | |
| 8736 | } | ||
| 8737 | 787596 | return nullptr; | |
| 8738 | } | ||
| 8739 | |||
| 8740 | 2503057 | bool ref_lookup_subsumes_comparison(Field *field, Item *right_item) { | |
| 8741 | 2503057 | right_item = right_item->real_item(); | |
| 8742 |
2/2✓ Branch 0 taken 1802831 times.
✓ Branch 1 taken 700246 times.
|
2503074 | if (right_item->type() == Item::FIELD_ITEM) |
| 8743 | 1802831 | return (field->eq_def(down_cast<Item_field *>(right_item)->field)); | |
| 8744 | /* remove equalities injected by IN->EXISTS transformation */ | ||
| 8745 |
2/2✓ Branch 0 taken 149 times.
✓ Branch 1 taken 700095 times.
|
700246 | else if (right_item->type() == Item::CACHE_ITEM) |
| 8746 | 149 | return down_cast<Item_cache *>(right_item)->eq_def(field); | |
| 8747 |
6/6✓ Branch 0 taken 700027 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 700008 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 700012 times.
✓ Branch 5 taken 83 times.
|
700095 | if (right_item->const_for_execution() && !right_item->is_null()) { |
| 8748 | /* | ||
| 8749 | We can remove all fields except: | ||
| 8750 | 1. String data types: | ||
| 8751 | - For BINARY/VARBINARY fields with equality against a | ||
| 8752 | string: Ref access can return more rows than match the | ||
| 8753 | string. The reason seems to be that the string constant | ||
| 8754 | is not "padded" to the full length of the field when | ||
| 8755 | setting up ref access. @todo Change how ref access for | ||
| 8756 | BINARY/VARBINARY fields are done so that only qualifying | ||
| 8757 | rows are returned from the storage engine. | ||
| 8758 | 2. Float data type: Comparison of float can differ | ||
| 8759 | - When we search "WHERE field=value" using an index, | ||
| 8760 | the "value" side is converted from double to float by | ||
| 8761 | Field_float::store(), then two floats are compared. | ||
| 8762 | - When we search "WHERE field=value" without indexes, | ||
| 8763 | the "field" side is converted from float to double by | ||
| 8764 | Field_float::val_real(), then two doubles are compared. | ||
| 8765 | */ | ||
| 8766 |
4/4✓ Branch 0 taken 29246 times.
✓ Branch 1 taken 670760 times.
✓ Branch 2 taken 731 times.
✓ Branch 3 taken 699274 times.
|
729257 | if (field->type() == MYSQL_TYPE_STRING && |
| 8767 |
2/2✓ Branch 0 taken 731 times.
✓ Branch 1 taken 28514 times.
|
29246 | field->charset()->pad_attribute == NO_PAD) { |
| 8768 | /* | ||
| 8769 | For "NO PAD" collations on CHAR columns, this function must return | ||
| 8770 | false, because removal of trailing space in CHAR columns makes the | ||
| 8771 | table value and the index value compare differently. As the column | ||
| 8772 | strips trailing spaces, it can return false candidates. Further | ||
| 8773 | comparison of the actual table values is required. | ||
| 8774 | */ | ||
| 8775 | 731 | return false; | |
| 8776 | } | ||
| 8777 | 699274 | if (!((field->type() == MYSQL_TYPE_STRING || // 1 | |
| 8778 |
2/2✓ Branch 0 taken 414971 times.
✓ Branch 1 taken 255793 times.
|
670762 | field->type() == MYSQL_TYPE_VARCHAR) && |
| 8779 |
6/6✓ Branch 0 taken 670762 times.
✓ Branch 1 taken 28514 times.
✓ Branch 2 taken 443463 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 699266 times.
✓ Branch 5 taken 12 times.
|
1813513 | field->binary()) && |
| 8780 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 699260 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
|
699256 | !(field->type() == MYSQL_TYPE_FLOAT && field->decimals() > 0)) // 2 |
| 8781 | { | ||
| 8782 | 699266 | return !right_item->save_in_field_no_warnings(field, true); | |
| 8783 | } | ||
| 8784 | } | ||
| 8785 | 95 | return false; | |
| 8786 | } | ||
| 8787 | |||
| 8788 | /** | ||
| 8789 | @brief | ||
| 8790 | Identify redundant predicates. | ||
| 8791 | |||
| 8792 | @details | ||
| 8793 | Test if the equality predicate 'left_item = right_item' is redundant | ||
| 8794 | due to a REF-access already being set up on the table, where 'left_item' is | ||
| 8795 | part of the REF-key being used, and 'right_item' is equal to the key value | ||
| 8796 | specified for that field in the key. | ||
| 8797 | In such cases the predicate is known to be 'true' for any rows retrieved | ||
| 8798 | from that table. Thus it is redundant. | ||
| 8799 | |||
| 8800 | @param left_item The Item_field possibly being part of A ref-KEY. | ||
| 8801 | @param right_item The equality value specified for 'left_item'. | ||
| 8802 | |||
| 8803 | @return 'true' if the predicate is redundant. | ||
| 8804 | |||
| 8805 | @note See comments in reduce_cond_for_table() about careful | ||
| 8806 | usage/modifications of test_if_ref(). | ||
| 8807 | */ | ||
| 8808 | |||
| 8809 | 3421459 | static bool test_if_ref(Item_field *left_item, Item *right_item) { | |
| 8810 |
2/2✓ Branch 0 taken 558 times.
✓ Branch 1 taken 3420901 times.
|
3421459 | if (left_item->depended_from) |
| 8811 | 558 | return false; // don't even read join_tab of inner subquery! | |
| 8812 | 3420901 | Field *field = left_item->field; | |
| 8813 | 3420901 | JOIN_TAB *join_tab = field->table->reginfo.join_tab; | |
| 8814 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3420886 times.
|
3420901 | if (join_tab == nullptr) return false; |
| 8815 | |||
| 8816 |
3/6✓ Branch 0 taken 3420914 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3420911 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3420912 times.
✗ Branch 5 not taken.
|
3420886 | ASSERT_BEST_REF_IN_JOIN_ORDER(join_tab->join()); |
| 8817 | |||
| 8818 | // No need to change const test | ||
| 8819 |
6/6✓ Branch 0 taken 3420678 times.
✓ Branch 1 taken 233 times.
✓ Branch 2 taken 3420474 times.
✓ Branch 3 taken 204 times.
✓ Branch 4 taken 3420475 times.
✓ Branch 5 taken 436 times.
|
6841589 | if (!field->table->const_table && |
| 8820 | /* "ref_or_null" implements "x=y or x is null", not "x=y" */ | ||
| 8821 | 3420678 | (join_tab->type() != JT_REF_OR_NULL)) { | |
| 8822 | 3420475 | Item *ref_item = part_of_refkey(field->table, &join_tab->ref(), field); | |
| 8823 |
4/4✓ Branch 0 taken 2632807 times.
✓ Branch 1 taken 787668 times.
✓ Branch 2 taken 2502880 times.
✓ Branch 3 taken 129903 times.
|
5923382 | return (ref_item && ref_item->eq(right_item, true) && |
| 8824 |
2/2✓ Branch 0 taken 2495138 times.
✓ Branch 1 taken 7769 times.
|
5923358 | ref_lookup_subsumes_comparison(field, right_item)); |
| 8825 | } | ||
| 8826 | 436 | return false; // keep predicate | |
| 8827 | } | ||
| 8828 | |||
| 8829 | /** | ||
| 8830 | @brief | ||
| 8831 | Remove redundant predicates from condition, return the reduced condition. | ||
| 8832 | |||
| 8833 | @details | ||
| 8834 | A predicate of the form 'field = value' may be redundant if the | ||
| 8835 | (ref-) access chosen for the table use an index containing 'field', | ||
| 8836 | where 'value' is specified as (part of) its ref-key. This method remove | ||
| 8837 | such redundant predicates, thus reducing the condition, possibly | ||
| 8838 | eliminating it entirely. | ||
| 8839 | |||
| 8840 | If comparing 'values' against outer-joined tables, these are possibly | ||
| 8841 | 'null-extended'. Thus the usage of these values in the ref-key, is not | ||
| 8842 | sufficient anymore to guarantee that 'field = value' is 'TRUE'. | ||
| 8843 | The 'null_extended' argument hold the table_map of any such possibly | ||
| 8844 | null-extended tables which are excluded from the above 'reduce' logic. | ||
| 8845 | |||
| 8846 | Any tables referred in Item_func_trig_cond(FOUND_MATCH) conditions are | ||
| 8847 | aggregated into this null_extended table_map. | ||
| 8848 | |||
| 8849 | @param cond The condition to be 'reduced'. | ||
| 8850 | @param null_extended table_map of possibly null-extended outer-tables. | ||
| 8851 | |||
| 8852 | @return The condition with redundant predicates removed, | ||
| 8853 | possibly nullptr. | ||
| 8854 | */ | ||
| 8855 | 6817517 | static Item *reduce_cond_for_table(Item *cond, table_map null_extended) { | |
| 8856 |
1/2✓ Branch 0 taken 6817529 times.
✗ Branch 1 not taken.
|
6817517 | DBUG_TRACE; |
| 8857 |
5/8✓ Branch 0 taken 6817529 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6817523 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
|
6817529 | DBUG_EXECUTE("where", |
| 8858 | print_where(current_thd, cond, "cond term", QT_ORDINARY);); | ||
| 8859 | |||
| 8860 |
3/4✓ Branch 0 taken 6817527 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1405331 times.
✓ Branch 3 taken 5412196 times.
|
6817529 | if (cond->type() == Item::COND_ITEM) { |
| 8861 | 1405331 | List<Item> *arguments = down_cast<Item_cond *>(cond)->argument_list(); | |
| 8862 |
1/2✓ Branch 0 taken 1405333 times.
✗ Branch 1 not taken.
|
1405332 | List_iterator<Item> li(*arguments); |
| 8863 |
3/4✓ Branch 0 taken 1405330 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1385199 times.
✓ Branch 3 taken 20131 times.
|
1405333 | if (down_cast<Item_cond *>(cond)->functype() == Item_func::COND_AND_FUNC) { |
| 8864 | Item *item; | ||
| 8865 |
2/2✓ Branch 0 taken 3598668 times.
✓ Branch 1 taken 1385198 times.
|
4983869 | while ((item = li++)) { |
| 8866 |
1/2✓ Branch 0 taken 3598676 times.
✗ Branch 1 not taken.
|
3598668 | Item *upd_item = reduce_cond_for_table(item, null_extended); |
| 8867 |
2/2✓ Branch 0 taken 1418163 times.
✓ Branch 1 taken 2180513 times.
|
3598676 | if (upd_item == nullptr) { |
| 8868 |
1/2✓ Branch 0 taken 1418157 times.
✗ Branch 1 not taken.
|
1418163 | li.remove(); |
| 8869 |
2/2✓ Branch 0 taken 2059 times.
✓ Branch 1 taken 2178454 times.
|
2180513 | } else if (upd_item != item) { |
| 8870 | 2059 | li.replace(upd_item); | |
| 8871 | } | ||
| 8872 | } | ||
| 8873 |
3/3✓ Branch 0 taken 291460 times.
✓ Branch 1 taken 274852 times.
✓ Branch 2 taken 818886 times.
|
1385198 | switch (arguments->elements) { |
| 8874 | 291460 | case 0: | |
| 8875 | 566329 | return nullptr; // All 'true' -> And-cond true | |
| 8876 | 274852 | case 1: | |
| 8877 | 274852 | return arguments->head(); | |
| 8878 | } | ||
| 8879 | } else { // Or list | ||
| 8880 | Item *item; | ||
| 8881 |
2/2✓ Branch 0 taken 50410 times.
✓ Branch 1 taken 20118 times.
|
70528 | while ((item = li++)) { |
| 8882 |
1/2✓ Branch 0 taken 50414 times.
✗ Branch 1 not taken.
|
50410 | Item *upd_item = reduce_cond_for_table(item, null_extended); |
| 8883 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 50397 times.
|
50414 | if (upd_item == nullptr) { |
| 8884 | 17 | return nullptr; // Term 'true' -> entire Or-cond true | |
| 8885 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 50337 times.
|
50397 | } else if (upd_item != item) { |
| 8886 | 60 | li.replace(upd_item); | |
| 8887 | } | ||
| 8888 | } | ||
| 8889 | } | ||
| 8890 |
3/4✓ Branch 0 taken 5412194 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5412177 times.
✓ Branch 3 taken 17 times.
|
5412196 | } else if (cond->type() == Item::FUNC_ITEM) { |
| 8891 | 5412177 | Item_func *func = down_cast<Item_func *>(cond); | |
| 8892 |
3/4✓ Branch 0 taken 5412159 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 409210 times.
✓ Branch 3 taken 5002949 times.
|
5412180 | if (func->functype() == Item_func::TRIG_COND_FUNC) { |
| 8893 | 409210 | Item_func_trig_cond *func_trig = down_cast<Item_func_trig_cond *>(func); | |
| 8894 |
2/2✓ Branch 0 taken 3902 times.
✓ Branch 1 taken 405304 times.
|
409211 | if (func_trig->get_trig_type() == Item_func_trig_cond::FOUND_MATCH) { |
| 8895 | /* | ||
| 8896 | All inner-tables are possible null-extended when evaluating | ||
| 8897 | the 'FOUND_MATCH'. Thus, predicates embedded in this trig_cond, | ||
| 8898 | referring these tables, should not be eliminated. | ||
| 8899 | -> Add to null_extended map. | ||
| 8900 | */ | ||
| 8901 |
1/2✓ Branch 0 taken 3902 times.
✗ Branch 1 not taken.
|
3902 | null_extended |= func_trig->get_inner_tables(); |
| 8902 | } | ||
| 8903 | |||
| 8904 |
1/2✓ Branch 0 taken 409222 times.
✗ Branch 1 not taken.
|
409206 | Item *cond_arg = func->arguments()[0]; |
| 8905 |
1/2✓ Branch 0 taken 409222 times.
✗ Branch 1 not taken.
|
409222 | Item *upd_arg = reduce_cond_for_table(cond_arg, null_extended); |
| 8906 |
2/2✓ Branch 0 taken 392504 times.
✓ Branch 1 taken 16718 times.
|
409222 | if (upd_arg == nullptr) { |
| 8907 | 392504 | return nullptr; | |
| 8908 | } | ||
| 8909 |
1/2✓ Branch 0 taken 16718 times.
✗ Branch 1 not taken.
|
16718 | func->arguments()[0] = upd_arg; |
| 8910 | } | ||
| 8911 | |||
| 8912 |
3/4✓ Branch 0 taken 5002952 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3269051 times.
✓ Branch 3 taken 1733901 times.
|
5002949 | else if (func->functype() == Item_func::EQ_FUNC) { |
| 8913 | /* | ||
| 8914 | Remove equalities that are guaranteed to be true by use of 'ref' access | ||
| 8915 | method. | ||
| 8916 | Note that ref access implements "table1.field1 <=> | ||
| 8917 | table2.indexed_field2", i.e. if it passed a NULL field1, it will return | ||
| 8918 | NULL indexed_field2 if there are. | ||
| 8919 | Thus the equality "table1.field1 = table2.indexed_field2", | ||
| 8920 | is equivalent to "ref access AND table1.field1 IS NOT NULL" | ||
| 8921 | i.e. "ref access and proper setting/testing of ref->null_rejecting". | ||
| 8922 | Thus, we must be careful, that when we remove equalities below we also | ||
| 8923 | set ref->null_rejecting, and test it at execution; otherwise wrong NULL | ||
| 8924 | matches appear. | ||
| 8925 | So: | ||
| 8926 | - for the optimization phase, the code which is below, and the code in | ||
| 8927 | test_if_ref(), and in add_key_field(), must be kept in sync: if the | ||
| 8928 | applicability conditions in one place are relaxed, they should also be | ||
| 8929 | relaxed elsewhere. | ||
| 8930 | - for the execution phase, all possible execution methods must test | ||
| 8931 | ref->null_rejecting. | ||
| 8932 | */ | ||
| 8933 |
2/4✓ Branch 0 taken 3269060 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3269058 times.
✗ Branch 3 not taken.
|
3269051 | Item *left_item = func->arguments()[0]->real_item(); |
| 8934 |
2/4✓ Branch 0 taken 3269059 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3269062 times.
✗ Branch 3 not taken.
|
3269058 | Item *right_item = func->arguments()[1]->real_item(); |
| 8935 |
1/2✓ Branch 0 taken 3269059 times.
✗ Branch 1 not taken.
|
3269062 | if ((left_item->type() == Item::FIELD_ITEM && |
| 8936 |
3/4✓ Branch 0 taken 3257769 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3257350 times.
✓ Branch 3 taken 419 times.
|
3257769 | !(left_item->used_tables() & null_extended) && |
| 8937 |
7/8✓ Branch 0 taken 3257769 times.
✓ Branch 1 taken 11290 times.
✓ Branch 2 taken 3257356 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 762741 times.
✓ Branch 5 taken 2494615 times.
✓ Branch 6 taken 2495130 times.
✓ Branch 7 taken 773938 times.
|
7300862 | test_if_ref(down_cast<Item_field *>(left_item), right_item)) || |
| 8938 |
3/4✓ Branch 0 taken 774453 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 165021 times.
✓ Branch 3 taken 609432 times.
|
774450 | (right_item->type() == Item::FIELD_ITEM && |
| 8939 |
3/4✓ Branch 0 taken 165021 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 164132 times.
✓ Branch 3 taken 889 times.
|
165021 | !(right_item->used_tables() & null_extended) && |
| 8940 |
3/4✓ Branch 0 taken 164132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 522 times.
✓ Branch 3 taken 163610 times.
|
164132 | test_if_ref(down_cast<Item_field *>(right_item), left_item))) { |
| 8941 | 2495130 | return nullptr; | |
| 8942 | } | ||
| 8943 | } | ||
| 8944 | } | ||
| 8945 | 3363578 | return cond; | |
| 8946 | 6817541 | } | |
| 8947 | |||
| 8948 | /** | ||
| 8949 | @brief | ||
| 8950 | Remove redundant predicates and cache constant expressions. | ||
| 8951 | |||
| 8952 | @details | ||
| 8953 | Do a final round on pushed down table conditions and HAVING | ||
| 8954 | clause. Optimize them for faster execution by removing | ||
| 8955 | predicates being obsolete due to the access path selected | ||
| 8956 | for the table. Constant expressions are also cached | ||
| 8957 | to avoid evaluating them for each row being compared. | ||
| 8958 | |||
| 8959 | @return False if success, True if error | ||
| 8960 | |||
| 8961 | @note This function is run after conditions have been pushed down to | ||
| 8962 | individual tables, so transformation is applied to JOIN_TAB::condition | ||
| 8963 | and not to the WHERE condition. | ||
| 8964 | */ | ||
| 8965 | 1813863 | bool JOIN::finalize_table_conditions() { | |
| 8966 | /* | ||
| 8967 | Unnecessary to reduce conditions for const tables as they are only | ||
| 8968 | evaluated once. | ||
| 8969 | */ | ||
| 8970 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1813882 times.
|
1813863 | assert(!plan_is_const()); |
| 8971 |
5/6✓ Branch 0 taken 1813879 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1813882 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1813877 times.
✓ Branch 5 taken 5 times.
|
1813882 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 8972 | |||
| 8973 | 1813880 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 8974 |
1/2✓ Branch 0 taken 1813883 times.
✗ Branch 1 not taken.
|
1813880 | Opt_trace_object trace_wrapper(trace); |
| 8975 |
1/2✓ Branch 0 taken 1813885 times.
✗ Branch 1 not taken.
|
1813883 | Opt_trace_array trace_tables(trace, "finalizing_table_conditions"); |
| 8976 | |||
| 8977 |
2/2✓ Branch 0 taken 6292002 times.
✓ Branch 1 taken 1813905 times.
|
8105907 | for (uint i = const_tables; i < tables; i++) { |
| 8978 | 6292002 | Item *condition = best_ref[i]->condition(); | |
| 8979 |
2/2✓ Branch 0 taken 3532794 times.
✓ Branch 1 taken 2759217 times.
|
6292011 | if (condition == nullptr) continue; |
| 8980 | |||
| 8981 | /* | ||
| 8982 | Table predicates known to be true by the selected | ||
| 8983 | (ref-)access method may be removed from the condition | ||
| 8984 | */ | ||
| 8985 |
1/2✓ Branch 0 taken 2759224 times.
✗ Branch 1 not taken.
|
2759217 | Opt_trace_object trace_cond(trace); |
| 8986 |
1/2✓ Branch 0 taken 2759229 times.
✗ Branch 1 not taken.
|
2759224 | trace_cond.add_utf8_table(best_ref[i]->table_ref); |
| 8987 |
1/2✓ Branch 0 taken 2759227 times.
✗ Branch 1 not taken.
|
2759229 | trace_cond.add("original_table_condition", condition); |
| 8988 | |||
| 8989 | /* | ||
| 8990 | Calculate the set of possibly NULL extended tables when 'condition' | ||
| 8991 | is evaluated. As it is evaluated on a found row from table, that | ||
| 8992 | table is subtracted from the nullable tables. Note that a FOUND_MATCH | ||
| 8993 | trigger is a special case, handled in reduce_cond_for_table(). | ||
| 8994 | */ | ||
| 8995 | const table_map null_extended = | ||
| 8996 | 2759227 | query_block->outer_join & ~best_ref[i]->table_ref->map(); | |
| 8997 |
1/2✓ Branch 0 taken 2759231 times.
✗ Branch 1 not taken.
|
2759226 | condition = reduce_cond_for_table(condition, null_extended); |
| 8998 |
3/4✓ Branch 0 taken 1390798 times.
✓ Branch 1 taken 1368433 times.
✓ Branch 2 taken 1390800 times.
✗ Branch 3 not taken.
|
2759231 | if (condition != nullptr) condition->update_used_tables(); |
| 8999 | |||
| 9000 | /* | ||
| 9001 | Cache constant expressions in table conditions. | ||
| 9002 | (Moved down from WHERE- and ON-clauses) | ||
| 9003 | */ | ||
| 9004 |
2/2✓ Branch 0 taken 1390800 times.
✓ Branch 1 taken 1368433 times.
|
2759233 | if (condition != nullptr) { |
| 9005 |
1/2✓ Branch 0 taken 1390794 times.
✗ Branch 1 not taken.
|
1390800 | cache_const_expr_arg cache_arg; |
| 9006 | 1390794 | cache_const_expr_arg *analyzer_arg = &cache_arg; | |
| 9007 |
1/2✓ Branch 0 taken 1390797 times.
✗ Branch 1 not taken.
|
1390794 | condition = condition->compile( |
| 9008 | &Item::cache_const_expr_analyzer, (uchar **)&analyzer_arg, | ||
| 9009 | &Item::cache_const_expr_transformer, (uchar *)&cache_arg); | ||
| 9010 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1390796 times.
|
1390797 | if (condition == nullptr) return true; |
| 9011 | } | ||
| 9012 | |||
| 9013 |
1/2✓ Branch 0 taken 2759220 times.
✗ Branch 1 not taken.
|
2759229 | trace_cond.add("final_table_condition ", condition); |
| 9014 | 2759220 | best_ref[i]->set_condition(condition); | |
| 9015 |
2/2✓ Branch 0 taken 2759228 times.
✓ Branch 1 taken 1 times.
|
2759234 | } |
| 9016 | |||
| 9017 | /* Cache constant expressions in HAVING-clauses. */ | ||
| 9018 |
2/2✓ Branch 0 taken 3526 times.
✓ Branch 1 taken 1810379 times.
|
1813905 | if (having_cond != nullptr) { |
| 9019 |
1/2✓ Branch 0 taken 3526 times.
✗ Branch 1 not taken.
|
3526 | cache_const_expr_arg cache_arg; |
| 9020 | 3526 | cache_const_expr_arg *analyzer_arg = &cache_arg; | |
| 9021 |
1/2✓ Branch 0 taken 3526 times.
✗ Branch 1 not taken.
|
3526 | having_cond = having_cond->compile( |
| 9022 | &Item::cache_const_expr_analyzer, (uchar **)&analyzer_arg, | ||
| 9023 | &Item::cache_const_expr_transformer, (uchar *)&cache_arg); | ||
| 9024 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3526 times.
|
3526 | if (having_cond == nullptr) return true; |
| 9025 | } | ||
| 9026 | 1813905 | return false; | |
| 9027 | 1813906 | } | |
| 9028 | |||
| 9029 | /** | ||
| 9030 | @brief | ||
| 9031 | Add keys to derived tables'/views' result tables in a list | ||
| 9032 | |||
| 9033 | @details | ||
| 9034 | This function generates keys for all derived tables/views of the query_block | ||
| 9035 | to which this join corresponds to with help of the TABLE_LIST:generate_keys | ||
| 9036 | function. | ||
| 9037 | |||
| 9038 | @return false all keys were successfully added. | ||
| 9039 | @return true OOM error | ||
| 9040 | */ | ||
| 9041 | |||
| 9042 | 3010 | bool JOIN::generate_derived_keys() { | |
| 9043 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3010 times.
|
3010 | assert(query_block->materialized_derived_table_count); |
| 9044 | |||
| 9045 |
2/2✓ Branch 0 taken 5434 times.
✓ Branch 1 taken 3010 times.
|
8444 | for (TABLE_LIST *table = query_block->leaf_tables; table; |
| 9046 | 5434 | table = table->next_leaf) { | |
| 9047 | 5434 | table->derived_keys_ready = true; | |
| 9048 | /* Process tables that aren't materialized yet. */ | ||
| 9049 |
5/6✓ Branch 0 taken 3181 times.
✓ Branch 1 taken 2253 times.
✓ Branch 2 taken 1803 times.
✓ Branch 3 taken 1378 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5434 times.
|
7237 | if (table->uses_materialization() && !table->table->is_created() && |
| 9050 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1803 times.
|
1803 | table->generate_keys()) |
| 9051 | ✗ | return true; | |
| 9052 | } | ||
| 9053 | 3010 | return false; | |
| 9054 | } | ||
| 9055 | |||
| 9056 | /** | ||
| 9057 | For each materialized derived table/view, informs every TABLE of the key it | ||
| 9058 | will (not) use, segregates used keys from unused keys in TABLE::key_info, | ||
| 9059 | and eliminates unused keys. | ||
| 9060 | */ | ||
| 9061 | |||
| 9062 | 145210 | void JOIN::finalize_derived_keys() { | |
| 9063 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 145210 times.
|
145210 | assert(query_block->materialized_derived_table_count); |
| 9064 |
4/6✓ Branch 0 taken 145210 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 145211 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 145210 times.
✓ Branch 5 taken 1 times.
|
145210 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 9065 | |||
| 9066 | 145210 | bool adjust_key_count = false; | |
| 9067 | 145210 | table_map processed_tables = 0; | |
| 9068 | |||
| 9069 |
2/2✓ Branch 0 taken 294054 times.
✓ Branch 1 taken 145212 times.
|
439266 | for (uint i = 0; i < tables; i++) { |
| 9070 | 294054 | JOIN_TAB *tab = best_ref[i]; | |
| 9071 | 294054 | TABLE *table = tab->table(); | |
| 9072 | 294055 | TABLE_LIST *table_ref = tab->table_ref; | |
| 9073 | /* | ||
| 9074 | Save chosen key description if: | ||
| 9075 | 1) it's a materialized derived table | ||
| 9076 | 2) it's not yet instantiated | ||
| 9077 | 3) some keys are defined for it | ||
| 9078 | */ | ||
| 9079 |
2/2✓ Branch 0 taken 145565 times.
✓ Branch 1 taken 2549 times.
|
148114 | if (table && table_ref->uses_materialization() && // (1) |
| 9080 |
6/6✓ Branch 0 taken 148114 times.
✓ Branch 1 taken 145941 times.
✓ Branch 2 taken 142713 times.
✓ Branch 3 taken 2853 times.
✓ Branch 4 taken 1542 times.
✓ Branch 5 taken 292514 times.
|
584882 | !table->is_created() && // (2) |
| 9081 |
2/2✓ Branch 0 taken 1542 times.
✓ Branch 1 taken 141171 times.
|
142713 | table->s->keys > 0) // (3) |
| 9082 | { | ||
| 9083 | /* | ||
| 9084 | If there are two local references to the same CTE, and they use | ||
| 9085 | the same key, the iteration for the second reference is unnecessary. | ||
| 9086 | */ | ||
| 9087 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1531 times.
|
2340 | if (processed_tables & table_ref->map()) continue; |
| 9088 | |||
| 9089 | 1531 | adjust_key_count = true; | |
| 9090 | |||
| 9091 |
1/2✓ Branch 0 taken 1531 times.
✗ Branch 1 not taken.
|
1531 | Key_map used_keys; |
| 9092 | |||
| 9093 | // Mark all unique indexes as in use, since they have an effect | ||
| 9094 | // (deduplication) whether any expression refers to them or not. | ||
| 9095 | // In particular, they are used if we want to materialize a UNION DISTINCT | ||
| 9096 | // directly into the derived table. | ||
| 9097 |
2/2✓ Branch 0 taken 10815 times.
✓ Branch 1 taken 1531 times.
|
12346 | for (uint key_idx = 0; key_idx < table->s->keys; ++key_idx) { |
| 9098 |
2/2✓ Branch 0 taken 261 times.
✓ Branch 1 taken 10554 times.
|
10815 | if (table->key_info[key_idx].flags & HA_NOSAME) { |
| 9099 | 261 | used_keys.set_bit(key_idx); | |
| 9100 | } | ||
| 9101 | } | ||
| 9102 | |||
| 9103 | // Same for the hash key used for manual deduplication, if any. (It always | ||
| 9104 | // has index 0 if it exists.) | ||
| 9105 |
2/2✓ Branch 0 taken 181 times.
✓ Branch 1 taken 1350 times.
|
1531 | if (table->hash_field) { |
| 9106 | 181 | used_keys.set_bit(0); | |
| 9107 | } | ||
| 9108 | |||
| 9109 | 1531 | Key_use *const keyuse = tab->position()->key; | |
| 9110 |
6/6✓ Branch 0 taken 798 times.
✓ Branch 1 taken 733 times.
✓ Branch 2 taken 385 times.
✓ Branch 3 taken 413 times.
✓ Branch 4 taken 385 times.
✓ Branch 5 taken 1146 times.
|
1531 | if (keyuse == nullptr && used_keys.is_clear_all()) { |
| 9111 | // Nothing uses any keys. | ||
| 9112 | 385 | tab->keys().clear_all(); | |
| 9113 | 385 | tab->const_keys.clear_all(); | |
| 9114 | 385 | continue; | |
| 9115 | } | ||
| 9116 | |||
| 9117 | 1146 | Derived_refs_iterator it(table_ref); | |
| 9118 |
3/4✓ Branch 0 taken 15331 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14185 times.
✓ Branch 3 taken 1146 times.
|
15331 | while (TABLE *t = it.get_next()) { |
| 9119 | /* | ||
| 9120 | Eliminate possible keys created by this JOIN and which it | ||
| 9121 | doesn't use. | ||
| 9122 | Collect all keys of this table which are used by any reference in | ||
| 9123 | this query block. Any other query block doesn't matter as: | ||
| 9124 | - either it was optimized before, so it's not using a key we may | ||
| 9125 | want to drop. | ||
| 9126 | - or it was optimized in this same window, so: | ||
| 9127 | * either we own the window, then any key we may want to | ||
| 9128 | drop is not visible to it. | ||
| 9129 | * or it owns the window, then we are using only existing | ||
| 9130 | keys. | ||
| 9131 | - or it will be optimized after, so it's not using any key yet. | ||
| 9132 | |||
| 9133 | used_keys is a mix of possible used keys and existing used keys. | ||
| 9134 | */ | ||
| 9135 |
2/2✓ Branch 0 taken 1193 times.
✓ Branch 1 taken 12992 times.
|
14185 | if (t->pos_in_table_list->query_block == query_block) { |
| 9136 | 1193 | JOIN_TAB *jtab = t->reginfo.join_tab; | |
| 9137 | 1193 | Key_use *keyuse_1 = jtab->position()->key; | |
| 9138 |
2/2✓ Branch 0 taken 754 times.
✓ Branch 1 taken 439 times.
|
1193 | if (keyuse_1) used_keys.set_bit(keyuse_1->key); |
| 9139 | } | ||
| 9140 | 14185 | } | |
| 9141 | |||
| 9142 |
1/2✓ Branch 0 taken 1146 times.
✗ Branch 1 not taken.
|
1146 | uint new_idx = table->s->find_first_unused_tmp_key( |
| 9143 | used_keys); // Also updates table->s->first_unused_tmp_key. | ||
| 9144 |
2/2✓ Branch 0 taken 413 times.
✓ Branch 1 taken 733 times.
|
1146 | if (keyuse == nullptr) { |
| 9145 | 413 | continue; | |
| 9146 | } | ||
| 9147 | |||
| 9148 | 733 | const uint old_idx = keyuse->key; | |
| 9149 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 733 times.
|
733 | assert(old_idx != new_idx); |
| 9150 | |||
| 9151 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 730 times.
|
733 | if (old_idx > new_idx) { |
| 9152 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | assert(table->s->owner_of_possible_tmp_keys == query_block); |
| 9153 | 3 | it.rewind(); | |
| 9154 |
3/4✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
|
7 | while (TABLE *t = it.get_next()) { |
| 9155 | /* | ||
| 9156 | Unlike the collection of used_keys, references from other query | ||
| 9157 | blocks must be considered here, as they need a key_info array | ||
| 9158 | consistent with the to-be-changed table->s->keys. | ||
| 9159 | */ | ||
| 9160 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | t->move_tmp_key(old_idx, it.is_first()); |
| 9161 | 4 | } | |
| 9162 | } else | ||
| 9163 | 730 | new_idx = old_idx; // Index stays at same slot | |
| 9164 | |||
| 9165 | /* | ||
| 9166 | If the key was created by earlier-optimized query blocks, and is | ||
| 9167 | already used by nonlocal references, those don't need any further | ||
| 9168 | update: they are already setup to use it and we're not moving the | ||
| 9169 | key. | ||
| 9170 | If the key was created by this query block, nonlocal references cannot | ||
| 9171 | possibly be referencing it. | ||
| 9172 | In both cases, only local references need to update their Key_use. | ||
| 9173 | */ | ||
| 9174 | 733 | it.rewind(); | |
| 9175 |
3/4✓ Branch 0 taken 14295 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13562 times.
✓ Branch 3 taken 733 times.
|
14295 | while (TABLE *t = it.get_next()) { |
| 9176 |
2/2✓ Branch 0 taken 12806 times.
✓ Branch 1 taken 756 times.
|
13562 | if (t->pos_in_table_list->query_block != query_block) continue; |
| 9177 | 756 | JOIN_TAB *jtab = t->reginfo.join_tab; | |
| 9178 | 756 | Key_use *keyuse_1 = jtab->position()->key; | |
| 9179 |
3/4✓ Branch 0 taken 744 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 744 times.
✗ Branch 3 not taken.
|
756 | if (keyuse_1 && keyuse_1->key == old_idx) { |
| 9180 | 744 | processed_tables |= t->pos_in_table_list->map(); | |
| 9181 | 744 | const bool key_is_const = jtab->const_keys.is_set(old_idx); | |
| 9182 | // tab->keys() was never set, so must be set | ||
| 9183 | 744 | jtab->keys().clear_all(); | |
| 9184 | 744 | jtab->keys().set_bit(new_idx); | |
| 9185 | 744 | jtab->const_keys.clear_all(); | |
| 9186 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 715 times.
|
744 | if (key_is_const) tab->const_keys.set_bit(new_idx); |
| 9187 | 744 | for (Key_use *kit = keyuse_1; | |
| 9188 |
4/4✓ Branch 0 taken 1124 times.
✓ Branch 1 taken 441 times.
✓ Branch 2 taken 821 times.
✓ Branch 3 taken 303 times.
|
1565 | kit->table_ref == jtab->table_ref && kit->key == old_idx; kit++) |
| 9189 | 821 | kit->key = new_idx; | |
| 9190 | } | ||
| 9191 | 13562 | } | |
| 9192 | } | ||
| 9193 | } | ||
| 9194 | |||
| 9195 |
2/2✓ Branch 0 taken 143780 times.
✓ Branch 1 taken 1432 times.
|
145212 | if (!adjust_key_count) return; |
| 9196 | |||
| 9197 | // Finally we know how many keys remain in the table. | ||
| 9198 |
2/2✓ Branch 0 taken 4701 times.
✓ Branch 1 taken 1432 times.
|
6133 | for (uint i = 0; i < tables; i++) { |
| 9199 | 4701 | JOIN_TAB *tab = best_ref[i]; | |
| 9200 | 4701 | TABLE *table = tab->table(); | |
| 9201 | 4701 | TABLE_LIST *table_ref = tab->table_ref; | |
| 9202 |
8/8✓ Branch 0 taken 2989 times.
✓ Branch 1 taken 1712 times.
✓ Branch 2 taken 1586 times.
✓ Branch 3 taken 1403 times.
✓ Branch 4 taken 1561 times.
✓ Branch 5 taken 25 times.
✓ Branch 6 taken 1541 times.
✓ Branch 7 taken 3160 times.
|
6262 | if (table && table_ref->uses_materialization() && !table->is_created() && |
| 9203 |
2/2✓ Branch 0 taken 1541 times.
✓ Branch 1 taken 20 times.
|
1561 | table->s->keys > 0) { |
| 9204 |
2/2✓ Branch 0 taken 355 times.
✓ Branch 1 taken 1186 times.
|
1541 | if (table->s->owner_of_possible_tmp_keys != query_block) continue; |
| 9205 | /* | ||
| 9206 | Release lock. As a bonus, avoid double work when this loop | ||
| 9207 | later processes another local reference to the same table (similar to | ||
| 9208 | the processed_tables map in the first loop). | ||
| 9209 | */ | ||
| 9210 | 1186 | table->s->owner_of_possible_tmp_keys = nullptr; | |
| 9211 | 1186 | Derived_refs_iterator it(table_ref); | |
| 9212 |
4/6✓ Branch 0 taken 22761 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21575 times.
✓ Branch 3 taken 1186 times.
✓ Branch 4 taken 21575 times.
✗ Branch 5 not taken.
|
22761 | while (TABLE *t = it.get_next()) t->drop_unused_tmp_keys(it.is_first()); |
| 9213 | } | ||
| 9214 | } | ||
| 9215 | } | ||
| 9216 | |||
| 9217 | /** | ||
| 9218 | @brief | ||
| 9219 | Extract a condition that can be checked after reading given table | ||
| 9220 | |||
| 9221 | @param thd Current session. | ||
| 9222 | @param cond Condition to analyze | ||
| 9223 | @param tables Tables for which "current field values" are available | ||
| 9224 | @param used_table Table(s) that we are extracting the condition for (may | ||
| 9225 | also include PSEUDO_TABLE_BITS, and may be zero) | ||
| 9226 | @param exclude_expensive_cond Do not push expensive conditions | ||
| 9227 | |||
| 9228 | @retval <>NULL Generated condition | ||
| 9229 | @retval = NULL Already checked, OR error | ||
| 9230 | |||
| 9231 | @details | ||
| 9232 | Extract the condition that can be checked after reading the table(s) | ||
| 9233 | specified in @c used_table, given that current-field values for tables | ||
| 9234 | specified in @c tables bitmap are available. | ||
| 9235 | If @c used_table is 0, extract conditions for all tables in @c tables. | ||
| 9236 | |||
| 9237 | This function can be used to extract conditions relevant for a table | ||
| 9238 | in a join order. Together with its caller, it will ensure that all | ||
| 9239 | conditions are attached to the first table in the join order where all | ||
| 9240 | necessary fields are available, and it will also ensure that a given | ||
| 9241 | condition is attached to only one table. | ||
| 9242 | To accomplish this, first initialize @c tables to the empty | ||
| 9243 | set. Then, loop over all tables in the join order, set @c used_table to | ||
| 9244 | the bit representing the current table, accumulate @c used_table into the | ||
| 9245 | @c tables set, and call this function. To ensure correct handling of | ||
| 9246 | const expressions and outer references, add the const table map and | ||
| 9247 | OUTER_REF_TABLE_BIT to @c used_table for the first table. To ensure | ||
| 9248 | that random expressions are evaluated for the final table, add | ||
| 9249 | RAND_TABLE_BIT to @c used_table for the final table. | ||
| 9250 | |||
| 9251 | The function assumes that constant, inexpensive parts of the condition | ||
| 9252 | have already been checked. Constant, expensive parts will be attached | ||
| 9253 | to the first table in the join order, provided that the above call | ||
| 9254 | sequence is followed. | ||
| 9255 | |||
| 9256 | The call order will ensure that conditions covering tables in @c tables | ||
| 9257 | minus those in @c used_table, have already been checked. | ||
| 9258 | |||
| 9259 | The function takes into account that some parts of the condition are | ||
| 9260 | guaranteed to be true by employed 'ref' access methods (the code that | ||
| 9261 | does this is located at the end, search down for "EQ_FUNC"). | ||
| 9262 | |||
| 9263 | @note | ||
| 9264 | make_cond_for_info_schema() uses an algorithm similar to | ||
| 9265 | make_cond_for_table(). | ||
| 9266 | */ | ||
| 9267 | |||
| 9268 | 27059002 | Item *make_cond_for_table(THD *thd, Item *cond, table_map tables, | |
| 9269 | table_map used_table, bool exclude_expensive_cond) { | ||
| 9270 | /* | ||
| 9271 | May encounter an Item_cache_int as "condition" here, so cannot | ||
| 9272 | assert that it satisfies is_bool_func(). | ||
| 9273 | */ | ||
| 9274 | /* | ||
| 9275 | Ignore this condition if | ||
| 9276 | 1. We are extracting conditions for a specific table, and | ||
| 9277 | 2. that table is not referenced by the condition, but not if | ||
| 9278 | 3. this is a constant condition not checked at optimization time and | ||
| 9279 | this is the first table we are extracting conditions for. | ||
| 9280 | (Assuming that used_table == tables for the first table.) | ||
| 9281 | */ | ||
| 9282 | 48200803 | if (used_table && // 1 | |
| 9283 |
6/6✓ Branch 0 taken 21141786 times.
✓ Branch 1 taken 5917216 times.
✓ Branch 2 taken 11638866 times.
✓ Branch 3 taken 9502913 times.
✓ Branch 4 taken 11638842 times.
✓ Branch 5 taken 15420182 times.
|
38697897 | !(cond->used_tables() & used_table) && // 2 |
| 9284 |
4/4✓ Branch 0 taken 108 times.
✓ Branch 1 taken 11638787 times.
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 56 times.
|
11638866 | !(cond->is_expensive() && used_table == tables)) // 3 |
| 9285 | 11638842 | return nullptr; | |
| 9286 | |||
| 9287 |
2/2✓ Branch 0 taken 3496799 times.
✓ Branch 1 taken 11923385 times.
|
15420182 | if (cond->type() == Item::COND_ITEM) { |
| 9288 |
2/2✓ Branch 0 taken 3456765 times.
✓ Branch 1 taken 40037 times.
|
3496799 | if (((Item_cond *)cond)->functype() == Item_func::COND_AND_FUNC) { |
| 9289 | /* Create new top level AND item */ | ||
| 9290 |
2/4✓ Branch 0 taken 3456764 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3456768 times.
✗ Branch 3 not taken.
|
3456765 | Item_cond_and *new_cond = new Item_cond_and; |
| 9291 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3456768 times.
|
3456768 | if (!new_cond) return nullptr; |
| 9292 |
1/2✓ Branch 0 taken 3456768 times.
✗ Branch 1 not taken.
|
3456768 | List_iterator<Item> li(*((Item_cond *)cond)->argument_list()); |
| 9293 | Item *item; | ||
| 9294 |
2/2✓ Branch 0 taken 21653542 times.
✓ Branch 1 taken 3456705 times.
|
25110289 | while ((item = li++)) { |
| 9295 |
1/2✓ Branch 0 taken 21653526 times.
✗ Branch 1 not taken.
|
21653542 | Item *fix = make_cond_for_table(thd, item, tables, used_table, |
| 9296 | exclude_expensive_cond); | ||
| 9297 |
3/4✓ Branch 0 taken 4132985 times.
✓ Branch 1 taken 17520541 times.
✓ Branch 2 taken 4132980 times.
✗ Branch 3 not taken.
|
21653526 | if (fix) new_cond->argument_list()->push_back(fix); |
| 9298 | } | ||
| 9299 |
3/3✓ Branch 0 taken 1375727 times.
✓ Branch 1 taken 858921 times.
✓ Branch 2 taken 1222121 times.
|
3456705 | switch (new_cond->argument_list()->elements) { |
| 9300 | 1375727 | case 0: | |
| 9301 | 1375727 | return nullptr; // Always true | |
| 9302 | 858921 | case 1: | |
| 9303 | 858921 | return new_cond->argument_list()->head(); | |
| 9304 | 1222121 | default: | |
| 9305 |
2/4✓ Branch 0 taken 1222108 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1222108 times.
|
1222121 | if (new_cond->fix_fields(thd, nullptr)) return nullptr; |
| 9306 | 1222108 | return new_cond; | |
| 9307 | } | ||
| 9308 | } else { // Or list | ||
| 9309 |
2/4✓ Branch 0 taken 40037 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40037 times.
✗ Branch 3 not taken.
|
40037 | Item_cond_or *new_cond = new Item_cond_or; |
| 9310 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40037 times.
|
40037 | if (!new_cond) return nullptr; |
| 9311 |
1/2✓ Branch 0 taken 40037 times.
✗ Branch 1 not taken.
|
40037 | List_iterator<Item> li(*((Item_cond *)cond)->argument_list()); |
| 9312 | Item *item; | ||
| 9313 |
2/2✓ Branch 0 taken 70548 times.
✓ Branch 1 taken 19816 times.
|
90364 | while ((item = li++)) { |
| 9314 |
1/2✓ Branch 0 taken 70548 times.
✗ Branch 1 not taken.
|
70548 | Item *fix = make_cond_for_table(thd, item, tables, table_map(0), |
| 9315 | exclude_expensive_cond); | ||
| 9316 |
2/2✓ Branch 0 taken 20221 times.
✓ Branch 1 taken 50327 times.
|
70548 | if (!fix) return nullptr; // Always true |
| 9317 |
1/2✓ Branch 0 taken 50327 times.
✗ Branch 1 not taken.
|
50327 | new_cond->argument_list()->push_back(fix); |
| 9318 | } | ||
| 9319 |
2/4✓ Branch 0 taken 19816 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19816 times.
|
19816 | if (new_cond->fix_fields(thd, nullptr)) return nullptr; |
| 9320 | 19816 | return new_cond; | |
| 9321 | } | ||
| 9322 | } | ||
| 9323 | |||
| 9324 | /* | ||
| 9325 | Omit this condition if | ||
| 9326 | 1. Some tables referred by the condition are not available, or | ||
| 9327 | 2. We are extracting conditions for all tables, the condition is | ||
| 9328 | considered 'expensive', and we want to delay evaluation of such | ||
| 9329 | conditions to the execution phase. | ||
| 9330 | */ | ||
| 9331 |
6/6✓ Branch 0 taken 4930677 times.
✓ Branch 1 taken 6992706 times.
✓ Branch 2 taken 143645 times.
✓ Branch 3 taken 4787032 times.
✓ Branch 4 taken 6992744 times.
✓ Branch 5 taken 4930639 times.
|
12067030 | if ((cond->used_tables() & ~tables) || // 1 |
| 9332 |
4/4✓ Branch 0 taken 90338 times.
✓ Branch 1 taken 53307 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 90300 times.
|
143645 | (!used_table && exclude_expensive_cond && cond->is_expensive())) // 2 |
| 9333 | 6992744 | return nullptr; | |
| 9334 | |||
| 9335 | 4930639 | return cond; | |
| 9336 | } | ||
| 9337 | |||
| 9338 | /** | ||
| 9339 | Separates the predicates in a join condition and pushes them to the | ||
| 9340 | join step where all involved tables are available in the join prefix. | ||
| 9341 | ON clauses from JOIN expressions are also pushed to the most appropriate step. | ||
| 9342 | |||
| 9343 | @param join Join object where predicates are pushed. | ||
| 9344 | |||
| 9345 | @param cond Pointer to condition which may contain an arbitrary number of | ||
| 9346 | predicates, combined using AND, OR and XOR items. | ||
| 9347 | If NULL, equivalent to a predicate that returns true for all | ||
| 9348 | row combinations. | ||
| 9349 | |||
| 9350 | |||
| 9351 | @retval true Found impossible WHERE clause, or out-of-memory | ||
| 9352 | @retval false Other | ||
| 9353 | */ | ||
| 9354 | |||
| 9355 | 1903440 | static bool make_join_query_block(JOIN *join, Item *cond) { | |
| 9356 |
4/6✓ Branch 0 taken 1302885 times.
✓ Branch 1 taken 600555 times.
✓ Branch 2 taken 1302895 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1302895 times.
|
1903440 | assert(cond == nullptr || cond->is_bool_func()); |
| 9357 | 1903450 | THD *thd = join->thd; | |
| 9358 | 1903450 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 9359 |
1/2✓ Branch 0 taken 1903458 times.
✗ Branch 1 not taken.
|
1903450 | DBUG_TRACE; |
| 9360 |
4/6✓ Branch 0 taken 1903458 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1903455 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1903455 times.
✗ Branch 5 not taken.
|
1903458 | ASSERT_BEST_REF_IN_JOIN_ORDER(join); |
| 9361 | |||
| 9362 | // Add IS NOT NULL conditions to table conditions: | ||
| 9363 |
2/4✓ Branch 0 taken 1903457 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1903457 times.
|
1903455 | if (add_not_null_conds(join)) return true; |
| 9364 | |||
| 9365 | /* | ||
| 9366 | Extract constant conditions that are part of the WHERE clause. | ||
| 9367 | Constant parts of join conditions from outer joins are attached to | ||
| 9368 | the appropriate table condition in JOIN::attach_join_conditions(). | ||
| 9369 | */ | ||
| 9370 |
2/2✓ Branch 0 taken 1302896 times.
✓ Branch 1 taken 600561 times.
|
1903457 | if (cond) /* Because of GroupIndexSkipScanIterator */ |
| 9371 | { /* there may be a select without a cond. */ | ||
| 9372 |
2/2✓ Branch 0 taken 452398 times.
✓ Branch 1 taken 850498 times.
|
1302896 | if (join->primary_tables > 1) |
| 9373 |
1/2✓ Branch 0 taken 452398 times.
✗ Branch 1 not taken.
|
452398 | cond->update_used_tables(); // Table number may have changed |
| 9374 |
4/4✓ Branch 0 taken 83928 times.
✓ Branch 1 taken 1218968 times.
✓ Branch 2 taken 82963 times.
✓ Branch 3 taken 1219934 times.
|
1386825 | if (join->plan_is_const() && |
| 9375 | 83928 | join->query_block->master_query_expression() == | |
| 9376 |
2/2✓ Branch 0 taken 82963 times.
✓ Branch 1 taken 966 times.
|
83929 | thd->lex->unit) // The outer-most query block |
| 9377 | 82963 | join->const_table_map |= RAND_TABLE_BIT; | |
| 9378 | } | ||
| 9379 | /* | ||
| 9380 | Extract conditions that depend on constant tables. | ||
| 9381 | The const part of the query's WHERE clause can be checked immediately | ||
| 9382 | and if it is not satisfied then the join has empty result | ||
| 9383 | */ | ||
| 9384 | 1903458 | Item *const_cond = nullptr; | |
| 9385 |
2/2✓ Branch 0 taken 1302897 times.
✓ Branch 1 taken 600561 times.
|
1903458 | if (cond) |
| 9386 |
1/2✓ Branch 0 taken 1302894 times.
✗ Branch 1 not taken.
|
1302897 | const_cond = make_cond_for_table(thd, cond, join->const_table_map, |
| 9387 | table_map(0), true); | ||
| 9388 | |||
| 9389 | // Add conditions added by add_not_null_conds() | ||
| 9390 |
2/2✓ Branch 0 taken 92245 times.
✓ Branch 1 taken 1903455 times.
|
1995700 | for (uint i = 0; i < join->const_tables; i++) { |
| 9391 |
2/4✓ Branch 0 taken 92245 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 92245 times.
|
92245 | if (and_conditions(&const_cond, join->best_ref[i]->condition())) |
| 9392 | ✗ | return true; | |
| 9393 | } | ||
| 9394 |
4/6✓ Branch 0 taken 1903455 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 1903430 times.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
|
1903455 | DBUG_EXECUTE("where", |
| 9395 | print_where(thd, const_cond, "constants", QT_ORDINARY);); | ||
| 9396 |
4/4✓ Branch 0 taken 88151 times.
✓ Branch 1 taken 1815298 times.
✓ Branch 2 taken 88151 times.
✓ Branch 3 taken 1815298 times.
|
1991600 | if (const_cond != nullptr && |
| 9397 |
2/4✓ Branch 0 taken 88151 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 88151 times.
✗ Branch 3 not taken.
|
88151 | evaluate_during_optimization(const_cond, join->query_block)) { |
| 9398 |
1/2✓ Branch 0 taken 88151 times.
✗ Branch 1 not taken.
|
88151 | const bool const_cond_result = const_cond->val_int() != 0; |
| 9399 |
3/4✓ Branch 0 taken 88151 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 88149 times.
|
91070 | if (thd->is_error()) return true; |
| 9400 | |||
| 9401 |
1/2✓ Branch 0 taken 88149 times.
✗ Branch 1 not taken.
|
88149 | Opt_trace_object trace_const_cond(trace); |
| 9402 | 176298 | trace_const_cond.add("condition_on_constant_tables", const_cond) | |
| 9403 |
2/4✓ Branch 0 taken 88149 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 88149 times.
✗ Branch 3 not taken.
|
88149 | .add("condition_value", const_cond_result); |
| 9404 |
2/2✓ Branch 0 taken 85230 times.
✓ Branch 1 taken 2919 times.
|
88149 | if (const_cond_result) { |
| 9405 | /* | ||
| 9406 | If all the tables referred by the condition are const tables and | ||
| 9407 | if the condition is not expensive, we can remove the where condition | ||
| 9408 | as it will always evaluate to "true". | ||
| 9409 | */ | ||
| 9410 | 85230 | if (join->plan_is_const() && | |
| 9411 |
7/8✓ Branch 0 taken 81007 times.
✓ Branch 1 taken 4223 times.
✓ Branch 2 taken 81007 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 81004 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 81003 times.
✓ Branch 7 taken 4227 times.
|
166234 | !(cond->used_tables() & ~join->const_table_map) && |
| 9412 |
3/4✓ Branch 0 taken 81004 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 81003 times.
✓ Branch 3 taken 1 times.
|
81004 | !cond->is_expensive()) { |
| 9413 |
3/8✓ Branch 0 taken 81003 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 81003 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 81003 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
81003 | DBUG_PRINT("info", ("Found always true WHERE condition")); |
| 9414 | 81003 | join->where_cond = nullptr; | |
| 9415 | } | ||
| 9416 | } else { | ||
| 9417 |
3/8✓ Branch 0 taken 2919 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2919 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2919 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
2919 | DBUG_PRINT("info", ("Found impossible WHERE condition")); |
| 9418 | 2919 | return true; | |
| 9419 | } | ||
| 9420 |
2/2✓ Branch 0 taken 85230 times.
✓ Branch 1 taken 2919 times.
|
88149 | } |
| 9421 | |||
| 9422 | /* | ||
| 9423 | Extract remaining conditions from WHERE clause and join conditions, | ||
| 9424 | and attach them to the most appropriate table condition. This means that | ||
| 9425 | a condition will be evaluated as soon as all fields it depends on are | ||
| 9426 | available. For outer join conditions, the additional criterion is that | ||
| 9427 | we must have determined whether outer-joined rows are available, or | ||
| 9428 | have been NULL-extended, see JOIN::attach_join_conditions() for details. | ||
| 9429 | */ | ||
| 9430 | { | ||
| 9431 |
1/2✓ Branch 0 taken 1900524 times.
✗ Branch 1 not taken.
|
1900528 | Opt_trace_object trace_wrapper(trace); |
| 9432 |
1/2✓ Branch 0 taken 1900538 times.
✗ Branch 1 not taken.
|
1900524 | Opt_trace_object trace_conditions(trace, "attaching_conditions_to_tables"); |
| 9433 |
1/2✓ Branch 0 taken 1900532 times.
✗ Branch 1 not taken.
|
1900538 | trace_conditions.add("original_condition", cond); |
| 9434 | Opt_trace_array trace_attached_comp(trace, | ||
| 9435 |
1/2✓ Branch 0 taken 1900536 times.
✗ Branch 1 not taken.
|
1900532 | "attached_conditions_computation"); |
| 9436 | |||
| 9437 |
2/2✓ Branch 0 taken 6381699 times.
✓ Branch 1 taken 1900549 times.
|
8282248 | for (uint i = join->const_tables; i < join->tables; i++) { |
| 9438 | 6381699 | JOIN_TAB *const tab = join->best_ref[i]; | |
| 9439 | |||
| 9440 |
2/2✓ Branch 0 taken 2555257 times.
✓ Branch 1 taken 3826462 times.
|
6381699 | if (!tab->position()) continue; |
| 9441 | /* | ||
| 9442 | first_inner is the X in queries like: | ||
| 9443 | SELECT * FROM t1 LEFT OUTER JOIN (t2 JOIN t3) ON X | ||
| 9444 | */ | ||
| 9445 | 3826462 | const plan_idx first_inner = tab->first_inner(); | |
| 9446 | 3826468 | const table_map used_tables = tab->prefix_tables(); | |
| 9447 | 3826471 | const table_map current_map = tab->added_tables(); | |
| 9448 | 3826474 | Item *tmp = nullptr; | |
| 9449 | |||
| 9450 |
2/2✓ Branch 0 taken 3218317 times.
✓ Branch 1 taken 608157 times.
|
3826474 | if (cond) |
| 9451 |
1/2✓ Branch 0 taken 3218312 times.
✗ Branch 1 not taken.
|
3218317 | tmp = make_cond_for_table(thd, cond, used_tables, current_map, false); |
| 9452 | /* Add conditions added by add_not_null_conds(). */ | ||
| 9453 |
2/4✓ Branch 0 taken 3826452 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3826452 times.
|
3826469 | if (and_conditions(&tmp, tab->condition())) return true; |
| 9454 | |||
| 9455 |
8/8✓ Branch 0 taken 3218302 times.
✓ Branch 1 taken 608150 times.
✓ Branch 2 taken 860343 times.
✓ Branch 3 taken 2357959 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 860350 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 3826459 times.
|
3826452 | if (cond && !tmp && tab->range_scan()) { // Outer join |
| 9456 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | assert(tab->type() == JT_RANGE || tab->type() == JT_INDEX_MERGE); |
| 9457 | /* | ||
| 9458 | Hack to handle the case where we only refer to a table | ||
| 9459 | in the ON part of an OUTER JOIN. In this case we want the code | ||
| 9460 | below to check if we should use 'quick' instead. | ||
| 9461 | */ | ||
| 9462 |
3/8✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
2 | DBUG_PRINT("info", ("Item_func_true")); |
| 9463 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | tmp = new Item_func_true(); // Always true |
| 9464 | } | ||
| 9465 |
5/6✓ Branch 0 taken 860343 times.
✓ Branch 1 taken 608147 times.
✓ Branch 2 taken 858047 times.
✓ Branch 3 taken 2301 times.
✓ Branch 4 taken 858056 times.
✗ Branch 5 not taken.
|
2326539 | if (tmp || !cond || tab->type() == JT_REF || |
| 9466 |
8/8✓ Branch 0 taken 1468490 times.
✓ Branch 1 taken 2357971 times.
✓ Branch 2 taken 467649 times.
✓ Branch 3 taken 390401 times.
✓ Branch 4 taken 9177 times.
✓ Branch 5 taken 458472 times.
✓ Branch 6 taken 3367990 times.
✓ Branch 7 taken 458472 times.
|
6153005 | tab->type() == JT_REF_OR_NULL || tab->type() == JT_EQ_REF || |
| 9467 | first_inner != NO_PLAN_IDX) { | ||
| 9468 |
4/6✓ Branch 0 taken 3367995 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 3367970 times.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
|
3367990 | DBUG_EXECUTE("where", |
| 9469 | print_where(thd, tmp, tab->table()->alias, QT_ORDINARY);); | ||
| 9470 | /* | ||
| 9471 | If tab is an inner table of an outer join operation, | ||
| 9472 | add a match guard to the pushed down predicate. | ||
| 9473 | The guard will turn the predicate on only after | ||
| 9474 | the first match for outer tables is encountered. | ||
| 9475 | */ | ||
| 9476 |
4/4✓ Branch 0 taken 2759839 times.
✓ Branch 1 taken 608152 times.
✓ Branch 2 taken 2357956 times.
✓ Branch 3 taken 401883 times.
|
3367991 | if (cond && tmp) { |
| 9477 | /* | ||
| 9478 | Because of GroupIndexSkipScanIterator there may be a select without | ||
| 9479 | a cond, so neutralize the hack above. | ||
| 9480 | */ | ||
| 9481 |
2/4✓ Branch 0 taken 2357941 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2357941 times.
|
2357956 | if (!(tmp = add_found_match_trig_cond(join, first_inner, tmp, |
| 9482 | NO_PLAN_IDX))) | ||
| 9483 | ✗ | return true; | |
| 9484 | 2357941 | tab->set_condition(tmp); | |
| 9485 | } else { | ||
| 9486 | 1010035 | tab->set_condition(nullptr); | |
| 9487 | } | ||
| 9488 | |||
| 9489 |
4/6✓ Branch 0 taken 3367996 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 3367971 times.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
|
3367999 | DBUG_EXECUTE("where", |
| 9490 | print_where(thd, tmp, tab->table()->alias, QT_ORDINARY);); | ||
| 9491 | |||
| 9492 |
2/2✓ Branch 0 taken 32149 times.
✓ Branch 1 taken 3335849 times.
|
3367996 | if (tab->range_scan()) { |
| 9493 |
3/6✓ Branch 0 taken 32149 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32149 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 32149 times.
|
32149 | if (tab->needed_reg.is_clear_all() && tab->type() != JT_CONST) { |
| 9494 | /* | ||
| 9495 | We keep (for now) the QUICK AM calculated in | ||
| 9496 | get_quick_record_count(). | ||
| 9497 | */ | ||
| 9498 | } else { | ||
| 9499 | ✗ | destroy(tab->range_scan()); | |
| 9500 | ✗ | tab->set_range_scan(nullptr); | |
| 9501 | } | ||
| 9502 | } | ||
| 9503 | |||
| 9504 |
4/4✓ Branch 0 taken 2060217 times.
✓ Branch 1 taken 31031 times.
✓ Branch 2 taken 2059105 times.
✓ Branch 3 taken 1118 times.
|
7519466 | if ((tab->type() == JT_ALL || tab->type() == JT_RANGE || |
| 9505 |
6/6✓ Branch 0 taken 2091245 times.
✓ Branch 1 taken 1276752 times.
✓ Branch 2 taken 37931 times.
✓ Branch 3 taken 2021168 times.
✓ Branch 4 taken 1345814 times.
✓ Branch 5 taken 2022186 times.
|
8834151 | tab->type() == JT_INDEX_MERGE || tab->type() == JT_INDEX_SCAN) && |
| 9506 |
2/2✓ Branch 0 taken 1345815 times.
✓ Branch 1 taken 1017 times.
|
1346832 | tab->use_quick != QS_RANGE) { |
| 9507 | /* | ||
| 9508 | We plan to scan (table/index/range scan). | ||
| 9509 | Check again if we should use an index. We can use an index if: | ||
| 9510 | |||
| 9511 | 1a) There is a condition that range optimizer can work on, and | ||
| 9512 | 1b) There are non-constant conditions on one or more keys, and | ||
| 9513 | 1c) Some of the non-constant fields may have been read | ||
| 9514 | already. This may be the case if this is not the first | ||
| 9515 | table in the join OR this is a subselect with | ||
| 9516 | non-constant conditions referring to an outer table | ||
| 9517 | (dependent subquery) | ||
| 9518 | or, | ||
| 9519 | 2a) There are conditions only relying on constants | ||
| 9520 | 2b) This is the first non-constant table | ||
| 9521 | 2c) There is a limit of rows to read that is lower than | ||
| 9522 | the fanout for this table, predicate filters included | ||
| 9523 | (i.e., the estimated number of rows that will be | ||
| 9524 | produced for this table per row combination of | ||
| 9525 | previous tables) | ||
| 9526 | 2d) The query is NOT run with FOUND_ROWS() (because in that | ||
| 9527 | case we have to scan through all rows to count them anyway) | ||
| 9528 | */ | ||
| 9529 | enum { | ||
| 9530 | DONT_RECHECK, | ||
| 9531 | NOT_FIRST_TABLE, | ||
| 9532 | LOW_LIMIT | ||
| 9533 | 1345814 | } recheck_reason = DONT_RECHECK; | |
| 9534 | |||
| 9535 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1345815 times.
|
1345814 | assert(tab->const_keys.is_subset(tab->keys())); |
| 9536 | |||
| 9537 | 1345815 | const join_type orig_join_type = tab->type(); | |
| 9538 | 1345817 | const AccessPath *const orig_range_scan = tab->range_scan(); | |
| 9539 | |||
| 9540 |
2/2✓ Branch 0 taken 63887 times.
✓ Branch 1 taken 673774 times.
|
737661 | if (cond && // 1a |
| 9541 |
6/6✓ Branch 0 taken 737661 times.
✓ Branch 1 taken 608155 times.
✓ Branch 2 taken 2390 times.
✓ Branch 3 taken 61497 times.
✓ Branch 4 taken 61551 times.
✓ Branch 5 taken 1284263 times.
|
2085865 | (tab->keys() != tab->const_keys) && // 1b |
| 9542 | 2390 | (i > 0 || // 1c | |
| 9543 |
2/2✓ Branch 0 taken 162 times.
✓ Branch 1 taken 2228 times.
|
2390 | (join->query_block->master_query_expression()->item && |
| 9544 |
3/4✓ Branch 0 taken 160 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 106 times.
|
162 | cond->is_outer_reference()))) |
| 9545 | 61551 | recheck_reason = NOT_FIRST_TABLE; | |
| 9546 | 1284263 | else if (!tab->const_keys.is_clear_all() && // 2a | |
| 9547 |
2/2✓ Branch 0 taken 197519 times.
✓ Branch 1 taken 502 times.
|
198021 | i == join->const_tables && // 2b |
| 9548 | 197519 | (join->query_expression()->select_limit_cnt < | |
| 9549 | 197519 | (tab->position()->rows_fetched * | |
| 9550 |
6/6✓ Branch 0 taken 198021 times.
✓ Branch 1 taken 1086240 times.
✓ Branch 2 taken 2434 times.
✓ Branch 3 taken 195085 times.
✓ Branch 4 taken 2429 times.
✓ Branch 5 taken 1281832 times.
|
1484716 | tab->position()->filter_effect)) && // 2c |
| 9551 |
2/2✓ Branch 0 taken 2429 times.
✓ Branch 1 taken 5 times.
|
2434 | !join->calc_found_rows) // 2d |
| 9552 | 2429 | recheck_reason = LOW_LIMIT; | |
| 9553 | |||
| 9554 | // Don't recheck if the storage engine does not support index access. | ||
| 9555 |
2/2✓ Branch 0 taken 307 times.
✓ Branch 1 taken 1345505 times.
|
1345812 | if ((tab->table()->file->ha_table_flags() & HA_NO_INDEX_ACCESS) != 0) |
| 9556 | 307 | recheck_reason = DONT_RECHECK; | |
| 9557 | |||
| 9558 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1345800 times.
|
1345812 | if (tab->position()->sj_strategy == SJ_OPT_LOOSE_SCAN) { |
| 9559 | /* | ||
| 9560 | Semijoin loose scan has settled for a certain index-based access | ||
| 9561 | method with suitable characteristics, don't substitute it. | ||
| 9562 | */ | ||
| 9563 | 17 | recheck_reason = DONT_RECHECK; | |
| 9564 | } | ||
| 9565 | |||
| 9566 |
2/2✓ Branch 0 taken 63966 times.
✓ Branch 1 taken 1281851 times.
|
1345817 | if (recheck_reason != DONT_RECHECK) { |
| 9567 |
1/2✓ Branch 0 taken 63966 times.
✗ Branch 1 not taken.
|
63966 | Opt_trace_object trace_one_table(trace); |
| 9568 |
1/2✓ Branch 0 taken 63966 times.
✗ Branch 1 not taken.
|
63966 | trace_one_table.add_utf8_table(tab->table_ref); |
| 9569 |
1/2✓ Branch 0 taken 63966 times.
✗ Branch 1 not taken.
|
63966 | Opt_trace_object trace_table(trace, "rechecking_index_usage"); |
| 9570 |
2/2✓ Branch 0 taken 61537 times.
✓ Branch 1 taken 2429 times.
|
63966 | if (recheck_reason == NOT_FIRST_TABLE) |
| 9571 |
1/2✓ Branch 0 taken 61537 times.
✗ Branch 1 not taken.
|
61537 | trace_table.add_alnum("recheck_reason", "not_first_table"); |
| 9572 | else | ||
| 9573 |
1/2✓ Branch 0 taken 2429 times.
✗ Branch 1 not taken.
|
2429 | trace_table.add_alnum("recheck_reason", "low_limit") |
| 9574 |
1/2✓ Branch 0 taken 2429 times.
✗ Branch 1 not taken.
|
2429 | .add("limit", join->query_expression()->select_limit_cnt) |
| 9575 | 2429 | .add("row_estimate", tab->position()->rows_fetched * | |
| 9576 |
1/2✓ Branch 0 taken 2429 times.
✗ Branch 1 not taken.
|
2429 | tab->position()->filter_effect); |
| 9577 | |||
| 9578 | /* Join with outer join condition */ | ||
| 9579 | 63966 | Item *orig_cond = tab->condition(); | |
| 9580 |
1/2✓ Branch 0 taken 63966 times.
✗ Branch 1 not taken.
|
63966 | tab->and_with_condition(tab->join_cond()); |
| 9581 | |||
| 9582 | /* | ||
| 9583 | We can't call sel->cond->fix_fields, | ||
| 9584 | as it will break tab->join_cond() if it's AND condition | ||
| 9585 | (fix_fields currently removes extra AND/OR levels). | ||
| 9586 | Yet attributes of the just built condition are not needed. | ||
| 9587 | Thus we call sel->cond->quick_fix_field for safety. | ||
| 9588 | */ | ||
| 9589 |
4/6✓ Branch 0 taken 63580 times.
✓ Branch 1 taken 386 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 63580 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 63966 times.
|
63966 | if (tab->condition() && !tab->condition()->fixed) |
| 9590 | ✗ | tab->condition()->quick_fix_field(); | |
| 9591 | |||
| 9592 | 63966 | Key_map usable_keys = tab->keys(); | |
| 9593 | 63966 | enum_order interesting_order = ORDER_NOT_RELEVANT; | |
| 9594 | |||
| 9595 |
2/2✓ Branch 0 taken 2429 times.
✓ Branch 1 taken 61537 times.
|
63966 | if (recheck_reason == LOW_LIMIT) { |
| 9596 | 2429 | int read_direction = 0; | |
| 9597 | |||
| 9598 | /* | ||
| 9599 | If the current plan is to use range, then check if the | ||
| 9600 | already selected index provides the order dictated by the | ||
| 9601 | ORDER BY clause. | ||
| 9602 | */ | ||
| 9603 |
6/6✓ Branch 0 taken 1441 times.
✓ Branch 1 taken 988 times.
✓ Branch 2 taken 1439 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1439 times.
✓ Branch 5 taken 990 times.
|
3870 | if (tab->range_scan() && |
| 9604 | 1441 | used_index(tab->range_scan()) != MAX_KEY) { | |
| 9605 | 1439 | const uint ref_key = used_index(tab->range_scan()); | |
| 9606 | bool skip_quick; | ||
| 9607 |
1/2✓ Branch 0 taken 1439 times.
✗ Branch 1 not taken.
|
1439 | read_direction = test_if_order_by_key( |
| 9608 | &join->order, tab->table(), ref_key, nullptr, &skip_quick); | ||
| 9609 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1439 times.
|
1439 | if (skip_quick) read_direction = 0; |
| 9610 | /* | ||
| 9611 | If the index provides order there is no need to recheck | ||
| 9612 | index usage; we already know from the former call to | ||
| 9613 | test_quick_select() that a range scan on the chosen | ||
| 9614 | index is cheapest. Note that previous calls to | ||
| 9615 | test_quick_select() did not take order direction | ||
| 9616 | (ASC/DESC) into account, so in case of DESC ordering | ||
| 9617 | we still need to recheck. | ||
| 9618 | */ | ||
| 9619 |
4/4✓ Branch 0 taken 747 times.
✓ Branch 1 taken 692 times.
✓ Branch 2 taken 692 times.
✓ Branch 3 taken 747 times.
|
2186 | if (read_direction == 1 || |
| 9620 |
3/4✓ Branch 0 taken 301 times.
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 301 times.
|
1048 | (read_direction == -1 && |
| 9621 | 301 | is_reverse_sorted_range(tab->range_scan()))) { | |
| 9622 | 692 | recheck_reason = DONT_RECHECK; | |
| 9623 | } | ||
| 9624 | } | ||
| 9625 | // We do a cost based search for an ordering index here. Do this | ||
| 9626 | // only if prefer_ordering_index switch is on or an index is | ||
| 9627 | // forced for order by | ||
| 9628 |
4/4✓ Branch 0 taken 1737 times.
✓ Branch 1 taken 692 times.
✓ Branch 2 taken 1735 times.
✓ Branch 3 taken 694 times.
|
4166 | if (recheck_reason != DONT_RECHECK && |
| 9629 |
4/4✓ Branch 0 taken 1735 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1733 times.
✓ Branch 3 taken 2 times.
|
3472 | (tab->table()->force_index_order || |
| 9630 | 1735 | thd->optimizer_switch_flag( | |
| 9631 | OPTIMIZER_SWITCH_PREFER_ORDERING_INDEX))) { | ||
| 9632 | 1735 | int best_key = -1; | |
| 9633 | ha_rows select_limit = | ||
| 9634 | 1735 | join->query_expression()->select_limit_cnt; | |
| 9635 | |||
| 9636 | /* Use index specified in FORCE INDEX FOR ORDER BY, if any. */ | ||
| 9637 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1733 times.
|
1735 | if (tab->table()->force_index_order) |
| 9638 | 2 | usable_keys.intersect(tab->table()->keys_in_use_for_order_by); | |
| 9639 | |||
| 9640 | // Do a cost based search on the indexes that give sort order. | ||
| 9641 |
1/2✓ Branch 0 taken 1735 times.
✗ Branch 1 not taken.
|
1735 | test_if_cheaper_ordering( |
| 9642 | tab, &join->order, tab->table(), usable_keys, -1, | ||
| 9643 | select_limit, &best_key, &read_direction, &select_limit); | ||
| 9644 |
2/2✓ Branch 0 taken 1062 times.
✓ Branch 1 taken 673 times.
|
1735 | if (best_key < 0) |
| 9645 | 1062 | recheck_reason = DONT_RECHECK; // No usable keys | |
| 9646 | else { | ||
| 9647 | // Only usable_key is the best_key chosen | ||
| 9648 | 673 | usable_keys.clear_all(); | |
| 9649 | 673 | usable_keys.set_bit(best_key); | |
| 9650 | 673 | interesting_order = | |
| 9651 |
2/2✓ Branch 0 taken 319 times.
✓ Branch 1 taken 354 times.
|
673 | (read_direction == -1 ? ORDER_DESC : ORDER_ASC); |
| 9652 | } | ||
| 9653 | } | ||
| 9654 | } | ||
| 9655 | |||
| 9656 | 63966 | bool search_if_impossible = recheck_reason != DONT_RECHECK; | |
| 9657 |
2/2✓ Branch 0 taken 62212 times.
✓ Branch 1 taken 1754 times.
|
63966 | if (search_if_impossible) { |
| 9658 |
2/2✓ Branch 0 taken 298 times.
✓ Branch 1 taken 61914 times.
|
62212 | if (tab->range_scan()) { |
| 9659 | 298 | destroy(tab->range_scan()); | |
| 9660 | 298 | tab->set_type(JT_ALL); | |
| 9661 | } | ||
| 9662 | AccessPath *range_scan; | ||
| 9663 | MEM_ROOT temp_mem_root(key_memory_test_quick_select_exec, | ||
| 9664 | 62212 | thd->variables.range_alloc_block_size); | |
| 9665 | 62212 | search_if_impossible = | |
| 9666 | 124424 | test_quick_select( | |
| 9667 | thd, thd->mem_root, &temp_mem_root, usable_keys, | ||
| 9668 |
1/2✓ Branch 0 taken 62212 times.
✗ Branch 1 not taken.
|
62212 | used_tables & ~tab->table_ref->map(), 0, |
| 9669 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 62212 times.
|
62212 | join->calc_found_rows |
| 9670 | ? HA_POS_ERROR | ||
| 9671 | 62212 | : join->query_expression()->select_limit_cnt, | |
| 9672 | false, // don't force quick range | ||
| 9673 | interesting_order, tab->table(), | ||
| 9674 | 62212 | tab->skip_records_in_range(), tab->condition(), | |
| 9675 | 62212 | &tab->needed_reg, tab->table()->force_index, | |
| 9676 | 62212 | join->query_block, &range_scan) < 0; | |
| 9677 | 62212 | tab->set_range_scan(range_scan); | |
| 9678 | 62212 | } | |
| 9679 | 63966 | tab->set_condition(orig_cond); | |
| 9680 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63966 times.
|
63966 | if (search_if_impossible) { |
| 9681 | /* | ||
| 9682 | Before reporting "Impossible WHERE" for the whole query | ||
| 9683 | we have to check isn't it only "impossible ON" instead | ||
| 9684 | */ | ||
| 9685 | ✗ | if (!tab->join_cond()) | |
| 9686 | ✗ | return true; // No ON, so it's really "impossible WHERE" | |
| 9687 | ✗ | Opt_trace_object trace_without_on(trace, "without_ON_clause"); | |
| 9688 | ✗ | if (tab->range_scan()) { | |
| 9689 | ✗ | destroy(tab->range_scan()); | |
| 9690 | ✗ | tab->set_type(JT_ALL); | |
| 9691 | } | ||
| 9692 | AccessPath *range_scan; | ||
| 9693 | MEM_ROOT temp_mem_root(key_memory_test_quick_select_exec, | ||
| 9694 | ✗ | thd->variables.range_alloc_block_size); | |
| 9695 | const bool impossible_where = | ||
| 9696 | ✗ | test_quick_select( | |
| 9697 | ✗ | thd, thd->mem_root, &temp_mem_root, tab->keys(), | |
| 9698 | ✗ | used_tables & ~tab->table_ref->map(), 0, | |
| 9699 | ✗ | join->calc_found_rows | |
| 9700 | ? HA_POS_ERROR | ||
| 9701 | ✗ | : join->query_expression()->select_limit_cnt, | |
| 9702 | false, // don't force quick range | ||
| 9703 | ORDER_NOT_RELEVANT, tab->table(), | ||
| 9704 | ✗ | tab->skip_records_in_range(), tab->condition(), | |
| 9705 | ✗ | &tab->needed_reg, tab->table()->force_index, | |
| 9706 | ✗ | join->query_block, &range_scan) < 0; | |
| 9707 | ✗ | tab->set_range_scan(range_scan); | |
| 9708 | ✗ | if (impossible_where) return true; // Impossible WHERE | |
| 9709 | } | ||
| 9710 | |||
| 9711 | /* | ||
| 9712 | Access method changed. This is after deciding join order | ||
| 9713 | and access method for all other tables so the info | ||
| 9714 | updated below will not have any effect on the execution | ||
| 9715 | plan. | ||
| 9716 | */ | ||
| 9717 |
2/2✓ Branch 0 taken 1536 times.
✓ Branch 1 taken 62430 times.
|
63966 | if (tab->range_scan()) |
| 9718 |
1/2✓ Branch 0 taken 1536 times.
✗ Branch 1 not taken.
|
1536 | tab->set_type(calc_join_type(tab->range_scan())); |
| 9719 | |||
| 9720 |
2/4✓ Branch 0 taken 63966 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63966 times.
✗ Branch 3 not taken.
|
63966 | } // end of "if (recheck_reason != DONT_RECHECK)" |
| 9721 | |||
| 9722 |
4/4✓ Branch 0 taken 1325746 times.
✓ Branch 1 taken 20072 times.
✓ Branch 2 taken 20487 times.
✓ Branch 3 taken 1325330 times.
|
2671562 | if (!tab->table()->quick_keys.is_subset(tab->checked_keys) || |
| 9723 |
2/2✓ Branch 0 taken 415 times.
✓ Branch 1 taken 1325330 times.
|
1325746 | !tab->needed_reg.is_subset(tab->checked_keys)) { |
| 9724 | 20487 | tab->keys().merge(tab->table()->quick_keys); | |
| 9725 | 20487 | tab->keys().merge(tab->needed_reg); | |
| 9726 | |||
| 9727 | /* | ||
| 9728 | The logic below for assigning tab->use_quick is strange. | ||
| 9729 | It bases the decision of which access method to use | ||
| 9730 | (dynamic range, range, scan) based on seemingly | ||
| 9731 | unrelated information like the presence of another index | ||
| 9732 | with too bad selectivity to be used. | ||
| 9733 | |||
| 9734 | Consider the following scenario: | ||
| 9735 | |||
| 9736 | The join optimizer has decided to use join order | ||
| 9737 | (t1,t2), and 'tab' is currently t2. Further, assume that | ||
| 9738 | there is a join condition between t1 and t2 using some | ||
| 9739 | range operator (e.g. "t1.x < t2.y"). | ||
| 9740 | |||
| 9741 | It has been decided that a table scan is best for t2. | ||
| 9742 | make_join_query_block() then reran the range optimizer a few | ||
| 9743 | lines up because there is an index 't2.good_idx' | ||
| 9744 | covering the t2.y column. If 'good_idx' is the only | ||
| 9745 | index in t2, the decision below will be to use dynamic | ||
| 9746 | range. However, if t2 also has another index 't2.other' | ||
| 9747 | which the range access method can be used on but | ||
| 9748 | selectivity is bad (#rows estimate is high), then table | ||
| 9749 | scan is chosen instead. | ||
| 9750 | |||
| 9751 | Thus, the choice of DYNAMIC RANGE vs SCAN depends on the | ||
| 9752 | presence of an index that has so bad selectivity that it | ||
| 9753 | will not be used anyway. | ||
| 9754 | */ | ||
| 9755 |
6/6✓ Branch 0 taken 424 times.
✓ Branch 1 taken 20063 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 416 times.
✓ Branch 4 taken 416 times.
✓ Branch 5 taken 20071 times.
|
20919 | if (!tab->needed_reg.is_clear_all() && |
| 9756 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
432 | (tab->table()->quick_keys.is_clear_all() || |
| 9757 | 8 | (tab->range_scan() && | |
| 9758 | ✗ | (tab->range_scan()->num_output_rows >= 100.0)))) { | |
| 9759 | 416 | tab->use_quick = QS_DYNAMIC_RANGE; | |
| 9760 | 416 | tab->set_type(JT_ALL); | |
| 9761 | } else | ||
| 9762 | 20071 | tab->use_quick = QS_RANGE; | |
| 9763 | } | ||
| 9764 | |||
| 9765 |
6/6✓ Branch 0 taken 1345533 times.
✓ Branch 1 taken 279 times.
✓ Branch 2 taken 286 times.
✓ Branch 3 taken 1345252 times.
✓ Branch 4 taken 565 times.
✓ Branch 5 taken 1345252 times.
|
2691355 | if (tab->type() != orig_join_type || |
| 9766 | 1345533 | tab->range_scan() != orig_range_scan) // Access method changed | |
| 9767 | 565 | tab->position()->filter_effect = COND_FILTER_STALE; | |
| 9768 | } | ||
| 9769 | } | ||
| 9770 | |||
| 9771 |
2/4✓ Branch 0 taken 3826455 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3826455 times.
|
3826475 | if (join->attach_join_conditions(i)) return true; |
| 9772 | } | ||
| 9773 |
1/2✓ Branch 0 taken 1900533 times.
✗ Branch 1 not taken.
|
1900549 | trace_attached_comp.end(); |
| 9774 | |||
| 9775 | /* | ||
| 9776 | In outer joins the loop above, in iteration for table #i, may push | ||
| 9777 | conditions to a table before #i. Thus, the processing below has to be in | ||
| 9778 | a separate loop: | ||
| 9779 | */ | ||
| 9780 | Opt_trace_array trace_attached_summary(trace, | ||
| 9781 |
1/2✓ Branch 0 taken 1900537 times.
✗ Branch 1 not taken.
|
1900533 | "attached_conditions_summary"); |
| 9782 |
2/2✓ Branch 0 taken 6381711 times.
✓ Branch 1 taken 1900550 times.
|
8282261 | for (uint i = join->const_tables; i < join->tables; i++) { |
| 9783 | 6381711 | JOIN_TAB *const tab = join->best_ref[i]; | |
| 9784 |
2/2✓ Branch 0 taken 2555260 times.
✓ Branch 1 taken 3826458 times.
|
6381711 | if (!tab->table()) continue; |
| 9785 | 3826458 | Item *const tab_cond = tab->condition(); | |
| 9786 |
1/2✓ Branch 0 taken 3826463 times.
✗ Branch 1 not taken.
|
3826466 | Opt_trace_object trace_one_table(trace); |
| 9787 |
2/4✓ Branch 0 taken 3826468 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3826468 times.
✗ Branch 3 not taken.
|
3826463 | trace_one_table.add_utf8_table(tab->table_ref).add("attached", tab_cond); |
| 9788 |
6/6✓ Branch 0 taken 2759240 times.
✓ Branch 1 taken 1067228 times.
✓ Branch 2 taken 2452 times.
✓ Branch 3 taken 2756788 times.
✓ Branch 4 taken 2452 times.
✓ Branch 5 taken 3824016 times.
|
3826468 | if (tab_cond && tab_cond->has_subquery()) // traverse only if needed |
| 9789 | { | ||
| 9790 | /* | ||
| 9791 | Why we pass walk_subquery=false: imagine | ||
| 9792 | WHERE t1.col IN (SELECT * FROM t2 | ||
| 9793 | WHERE t2.col IN (SELECT * FROM t3) | ||
| 9794 | and tab==t1. The grandchild subquery (SELECT * FROM t3) should not | ||
| 9795 | be marked as "in condition of t1" but as "in condition of t2", for | ||
| 9796 | correct calculation of the number of its executions. | ||
| 9797 | */ | ||
| 9798 | 2452 | std::pair<Query_block *, int> pair_object(join->query_block, i); | |
| 9799 |
1/2✓ Branch 0 taken 2452 times.
✗ Branch 1 not taken.
|
2452 | tab_cond->walk(&Item::inform_item_in_cond_of_tab, enum_walk::POSTFIX, |
| 9800 | pointer_cast<uchar *>(&pair_object)); | ||
| 9801 | } | ||
| 9802 | 3826468 | } | |
| 9803 |
4/6✓ Branch 0 taken 1900532 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1900536 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1900537 times.
✗ Branch 5 not taken.
|
1900554 | } |
| 9804 | 1900537 | return false; | |
| 9805 | 1903458 | } | |
| 9806 | |||
| 9807 | /** | ||
| 9808 | Remove the following expressions from ORDER BY and GROUP BY: | ||
| 9809 | Constant expressions @n | ||
| 9810 | Expression that only uses tables that are of type EQ_REF and the reference | ||
| 9811 | is in the ORDER list or if all refereed tables are of the above type. | ||
| 9812 | |||
| 9813 | In the following, the X field can be removed: | ||
| 9814 | @code | ||
| 9815 | SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t1.a,t2.X | ||
| 9816 | SELECT * FROM t1,t2,t3 WHERE t1.a=t2.a AND t2.b=t3.b ORDER BY t1.a,t3.X | ||
| 9817 | @endcode | ||
| 9818 | |||
| 9819 | These can't be optimized: | ||
| 9820 | @code | ||
| 9821 | SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t2.X,t1.a | ||
| 9822 | SELECT * FROM t1,t2 WHERE t1.a=t2.a AND t1.b=t2.b ORDER BY t1.a,t2.c | ||
| 9823 | SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t2.b,t1.a | ||
| 9824 | @endcode | ||
| 9825 | |||
| 9826 | @param join join object | ||
| 9827 | @param start_order clause being analyzed (ORDER BY, GROUP BY...) | ||
| 9828 | @param tab table | ||
| 9829 | @param cached_eq_ref_tables bitmap: bit Z is set if the table of map Z | ||
| 9830 | was already the subject of an eq_ref_table() call for the same clause; then | ||
| 9831 | the return value of this previous call can be found at bit Z of | ||
| 9832 | 'eq_ref_tables' | ||
| 9833 | @param eq_ref_tables see above. | ||
| 9834 | */ | ||
| 9835 | |||
| 9836 | 418840 | static bool eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab, | |
| 9837 | table_map *cached_eq_ref_tables, | ||
| 9838 | table_map *eq_ref_tables) { | ||
| 9839 | /* We can skip const tables only if not an outer table */ | ||
| 9840 |
6/6✓ Branch 0 taken 10 times.
✓ Branch 1 taken 418830 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 418839 times.
|
418840 | if (tab->type() == JT_CONST && tab->first_inner() == NO_PLAN_IDX) return true; |
| 9841 |
6/6✓ Branch 0 taken 116560 times.
✓ Branch 1 taken 302279 times.
✓ Branch 2 taken 277 times.
✓ Branch 3 taken 116283 times.
✓ Branch 4 taken 302556 times.
✓ Branch 5 taken 116283 times.
|
418839 | if (tab->type() != JT_EQ_REF || tab->table()->is_nullable()) return false; |
| 9842 | |||
| 9843 | 116283 | const table_map map = tab->table_ref->map(); | |
| 9844 | 116283 | uint found = 0; | |
| 9845 | |||
| 9846 | 116335 | for (Item **ref_item = tab->ref().items, | |
| 9847 | 116283 | **end = ref_item + tab->ref().key_parts; | |
| 9848 |
2/2✓ Branch 0 taken 116283 times.
✓ Branch 1 taken 52 times.
|
116335 | ref_item != end; ref_item++) { |
| 9849 |
1/2✓ Branch 0 taken 116283 times.
✗ Branch 1 not taken.
|
116283 | if (!(*ref_item)->const_item()) { // Not a const ref |
| 9850 | ORDER *order; | ||
| 9851 |
2/2✓ Branch 0 taken 321087 times.
✓ Branch 1 taken 116234 times.
|
437321 | for (order = start_order; order; order = order->next) { |
| 9852 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 321038 times.
|
321087 | if ((*ref_item)->eq(order->item[0], false)) break; |
| 9853 | } | ||
| 9854 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 116234 times.
|
116283 | if (order) { |
| 9855 |
1/2✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
|
49 | if (!(order->used & map)) { |
| 9856 | 49 | found++; | |
| 9857 | 49 | order->used |= map; | |
| 9858 | } | ||
| 9859 | 49 | continue; // Used in ORDER BY | |
| 9860 | } | ||
| 9861 |
2/2✓ Branch 0 taken 116231 times.
✓ Branch 1 taken 3 times.
|
116234 | if (!only_eq_ref_tables(join, start_order, (*ref_item)->used_tables(), |
| 9862 | cached_eq_ref_tables, eq_ref_tables)) | ||
| 9863 | 116231 | return false; | |
| 9864 | } | ||
| 9865 | } | ||
| 9866 | /* Check that there was no reference to table before sort order */ | ||
| 9867 |
3/4✓ Branch 0 taken 85 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 85 times.
✗ Branch 3 not taken.
|
95 | for (; found && start_order; start_order = start_order->next) { |
| 9868 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 78 times.
|
85 | if (start_order->used & map) { |
| 9869 | 7 | found--; | |
| 9870 | 7 | continue; | |
| 9871 | } | ||
| 9872 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 36 times.
|
78 | if (start_order->depend_map & map) return false; |
| 9873 | } | ||
| 9874 | 10 | return true; | |
| 9875 | } | ||
| 9876 | |||
| 9877 | /// @see eq_ref_table() | ||
| 9878 | 537768 | static bool only_eq_ref_tables(JOIN *join, ORDER *order, table_map tables, | |
| 9879 | table_map *cached_eq_ref_tables, | ||
| 9880 | table_map *eq_ref_tables) { | ||
| 9881 | 537768 | tables &= ~PSEUDO_TABLE_BITS; | |
| 9882 |
2/2✓ Branch 0 taken 748789 times.
✓ Branch 1 taken 11 times.
|
748800 | for (JOIN_TAB **tab = join->map2table; tables; tab++, tables >>= 1) { |
| 9883 |
2/2✓ Branch 0 taken 537768 times.
✓ Branch 1 taken 211021 times.
|
748789 | if (tables & 1) { |
| 9884 | 537768 | const table_map map = (*tab)->table_ref->map(); | |
| 9885 | bool is_eq_ref; | ||
| 9886 |
2/2✓ Branch 0 taken 118928 times.
✓ Branch 1 taken 418840 times.
|
537768 | if (*cached_eq_ref_tables & map) // then there exists a cached bit |
| 9887 | 118928 | is_eq_ref = *eq_ref_tables & map; | |
| 9888 | else { | ||
| 9889 | 418840 | is_eq_ref = eq_ref_table(join, order, *tab, cached_eq_ref_tables, | |
| 9890 | eq_ref_tables); | ||
| 9891 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 418829 times.
|
418840 | if (is_eq_ref) |
| 9892 | 11 | *eq_ref_tables |= map; | |
| 9893 | else | ||
| 9894 | 418829 | *eq_ref_tables &= ~map; | |
| 9895 | 418840 | *cached_eq_ref_tables |= map; // now there exists a cached bit | |
| 9896 | } | ||
| 9897 |
2/2✓ Branch 0 taken 537757 times.
✓ Branch 1 taken 11 times.
|
537768 | if (!is_eq_ref) return false; |
| 9898 | } | ||
| 9899 | } | ||
| 9900 | 11 | return true; | |
| 9901 | } | ||
| 9902 | |||
| 9903 | /** | ||
| 9904 | Check if an expression in ORDER BY or GROUP BY is a duplicate of a | ||
| 9905 | preceding expression. | ||
| 9906 | |||
| 9907 | @param first_order the first expression in the ORDER BY or | ||
| 9908 | GROUP BY clause | ||
| 9909 | @param possible_dup the expression that might be a duplicate of | ||
| 9910 | another expression preceding it the ORDER BY | ||
| 9911 | or GROUP BY clause | ||
| 9912 | |||
| 9913 | @returns true if possible_dup is a duplicate, false otherwise | ||
| 9914 | */ | ||
| 9915 | 1022444 | static bool duplicate_order(const ORDER *first_order, | |
| 9916 | const ORDER *possible_dup) { | ||
| 9917 | const ORDER *order; | ||
| 9918 |
1/2✓ Branch 0 taken 2660974 times.
✗ Branch 1 not taken.
|
2660974 | for (order = first_order; order; order = order->next) { |
| 9919 |
2/2✓ Branch 0 taken 1022282 times.
✓ Branch 1 taken 1638692 times.
|
2660974 | if (order == possible_dup) { |
| 9920 | // all expressions preceding possible_dup have been checked. | ||
| 9921 | 1022282 | return false; | |
| 9922 | } else { | ||
| 9923 | 1638692 | const Item *it1 = order->item[0]->real_item(); | |
| 9924 | 1638692 | const Item *it2 = possible_dup->item[0]->real_item(); | |
| 9925 | |||
| 9926 |
2/2✓ Branch 0 taken 162 times.
✓ Branch 1 taken 1638530 times.
|
1638692 | if (it1->eq(it2, false)) return true; |
| 9927 | } | ||
| 9928 | } | ||
| 9929 | ✗ | return false; | |
| 9930 | } | ||
| 9931 | |||
| 9932 | /** | ||
| 9933 | Remove all constants and check if ORDER only contains simple | ||
| 9934 | expressions. | ||
| 9935 | |||
| 9936 | simple_order is set to true if sort_order only uses fields from head table | ||
| 9937 | and the head table is not a LEFT JOIN table. | ||
| 9938 | |||
| 9939 | @param first_order List of GROUP BY or ORDER BY sub-clauses. | ||
| 9940 | @param cond WHERE condition. | ||
| 9941 | @param change If true, remove sub-clauses that need not be evaluated. | ||
| 9942 | If this is not set, then only simple_order is calculated. | ||
| 9943 | @param[out] simple_order Set to true if we are only using simple expressions. | ||
| 9944 | @param group_by True if first_order represents a grouping operation. | ||
| 9945 | |||
| 9946 | @returns new sort order, after const elimination (when change is true). | ||
| 9947 | */ | ||
| 9948 | |||
| 9949 | 3801040 | ORDER *JOIN::remove_const(ORDER *first_order, Item *cond, bool change, | |
| 9950 | bool *simple_order, bool group_by) { | ||
| 9951 |
1/2✓ Branch 0 taken 3801073 times.
✗ Branch 1 not taken.
|
3801040 | DBUG_TRACE; |
| 9952 | |||
| 9953 |
4/6✓ Branch 0 taken 3801074 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3801074 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3801070 times.
✓ Branch 5 taken 4 times.
|
3801073 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 9954 | |||
| 9955 |
2/2✓ Branch 0 taken 173286 times.
✓ Branch 1 taken 3627787 times.
|
3801069 | if (plan_is_const()) |
| 9956 |
2/2✓ Branch 0 taken 173278 times.
✓ Branch 1 taken 8 times.
|
173286 | return change ? nullptr : first_order; // No need to sort |
| 9957 | |||
| 9958 | 3627787 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 9959 |
1/2✓ Branch 0 taken 3627780 times.
✗ Branch 1 not taken.
|
3627787 | Opt_trace_disable_I_S trace_disabled(trace, first_order == nullptr); |
| 9960 | Opt_trace_object trace_simpl( | ||
| 9961 |
3/4✓ Branch 0 taken 1813895 times.
✓ Branch 1 taken 1813885 times.
✓ Branch 2 taken 3627785 times.
✗ Branch 3 not taken.
|
3627780 | trace, group_by ? "simplifying_group_by" : "simplifying_order_by"); |
| 9962 |
2/2✓ Branch 0 taken 5238 times.
✓ Branch 1 taken 3622550 times.
|
3627785 | if (trace->is_started()) { |
| 9963 | 5238 | String str; | |
| 9964 | 5238 | Query_block::print_order( | |
| 9965 |
1/2✓ Branch 0 taken 5238 times.
✗ Branch 1 not taken.
|
5238 | thd, &str, first_order, |
| 9966 | enum_query_type(QT_TO_SYSTEM_CHARSET | QT_SHOW_SELECT_NUMBER | | ||
| 9967 | QT_NO_DEFAULT_DB)); | ||
| 9968 |
1/2✓ Branch 0 taken 5238 times.
✗ Branch 1 not taken.
|
5238 | trace_simpl.add_utf8("original_clause", str.ptr(), str.length()); |
| 9969 | 5238 | } | |
| 9970 |
1/2✓ Branch 0 taken 3627786 times.
✗ Branch 1 not taken.
|
3627788 | Opt_trace_array trace_each_item(trace, "items"); |
| 9971 | |||
| 9972 | 3627786 | JOIN_TAB *const first_tab = best_ref[const_tables]; | |
| 9973 | 3627786 | table_map first_table = first_tab->table_ref->map(); | |
| 9974 | 3627789 | table_map not_const_tables = ~const_table_map; | |
| 9975 | table_map ref; | ||
| 9976 | // Caches to avoid repeating eq_ref_table() calls, @see eq_ref_table() | ||
| 9977 | 3627789 | table_map eq_ref_tables = 0, cached_eq_ref_tables = 0; | |
| 9978 | |||
| 9979 | 3627789 | ORDER **prev_ptr = &first_order; | |
| 9980 | 3627789 | *simple_order = !first_tab->join_cond(); | |
| 9981 | |||
| 9982 | // De-optimization in conjunction with window functions | ||
| 9983 |
4/4✓ Branch 0 taken 1813896 times.
✓ Branch 1 taken 1813893 times.
✓ Branch 2 taken 1260 times.
✓ Branch 3 taken 1812636 times.
|
3627789 | if (group_by && m_windows.elements > 0) *simple_order = false; |
| 9984 | |||
| 9985 |
1/2✓ Branch 0 taken 3627788 times.
✗ Branch 1 not taken.
|
3627789 | update_depend_map(first_order); |
| 9986 | |||
| 9987 |
2/2✓ Branch 0 taken 1023216 times.
✓ Branch 1 taken 3627787 times.
|
4651003 | for (ORDER *order = first_order; order; order = order->next) { |
| 9988 |
1/2✓ Branch 0 taken 1023216 times.
✗ Branch 1 not taken.
|
1023216 | Opt_trace_object trace_one_item(trace); |
| 9989 |
1/2✓ Branch 0 taken 1023216 times.
✗ Branch 1 not taken.
|
1023216 | trace_one_item.add("item", order->item[0]); |
| 9990 |
1/2✓ Branch 0 taken 1023216 times.
✗ Branch 1 not taken.
|
1023216 | table_map order_tables = order->item[0]->used_tables(); |
| 9991 | |||
| 9992 |
6/6✓ Branch 0 taken 1022897 times.
✓ Branch 1 taken 318 times.
✓ Branch 2 taken 1022834 times.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 393 times.
✓ Branch 5 taken 1022823 times.
|
2046050 | if (order->item[0]->has_aggregation() || order->item[0]->has_wf() || |
| 9993 | /* | ||
| 9994 | If the outer table of an outer join is const (either by itself or | ||
| 9995 | after applying WHERE condition), grouping on a field from such a | ||
| 9996 | table will be optimized away and filesort without temporary table | ||
| 9997 | will be used unless we prevent that now. Filesort is not fit to | ||
| 9998 | handle joins and the join condition is not applied. We can't detect | ||
| 9999 | the case without an expensive test, however, so we force temporary | ||
| 10000 | table for all queries containing more than one table, ROLLUP, and an | ||
| 10001 | outer join. | ||
| 10002 | */ | ||
| 10003 |
4/4✓ Branch 0 taken 461806 times.
✓ Branch 1 taken 561028 times.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 461757 times.
|
1022834 | (primary_tables > 1 && rollup_state == RollupState::INITED && |
| 10004 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 38 times.
|
49 | query_block->outer_join)) { |
| 10005 | 393 | *simple_order = false; // Must use a temporary table to sort | |
| 10006 |
4/4✓ Branch 0 taken 379 times.
✓ Branch 1 taken 1022444 times.
✓ Branch 2 taken 377 times.
✓ Branch 3 taken 1022446 times.
|
1023202 | } else if ((order_tables & not_const_tables) == 0 && |
| 10007 |
3/4✓ Branch 0 taken 379 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 377 times.
✓ Branch 3 taken 2 times.
|
379 | evaluate_during_optimization(order->item[0], query_block)) { |
| 10008 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 340 times.
|
377 | if (order->item[0]->has_subquery()) { |
| 10009 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 5 times.
|
37 | if (!thd->lex->is_explain()) { |
| 10010 |
1/2✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
|
32 | Opt_trace_array trace_subselect(trace, "subselect_evaluation"); |
| 10011 | 32 | String str; | |
| 10012 |
1/2✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
|
32 | order->item[0]->val_str(&str); |
| 10013 | 32 | } | |
| 10014 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | order->item[0]->mark_subqueries_optimized_away(); |
| 10015 | } | ||
| 10016 |
1/2✓ Branch 0 taken 377 times.
✗ Branch 1 not taken.
|
377 | trace_one_item.add("uses_only_constant_tables", true); |
| 10017 | 377 | continue; // skip const item | |
| 10018 |
3/4✓ Branch 0 taken 1022444 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 1022282 times.
|
1022823 | } else if (duplicate_order(first_order, order)) { |
| 10019 | /* | ||
| 10020 | If 'order' is a duplicate of an expression earlier in the | ||
| 10021 | ORDER/GROUP BY sequence, it can be removed from the ORDER BY | ||
| 10022 | or GROUP BY clause. | ||
| 10023 | */ | ||
| 10024 |
1/2✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
|
162 | trace_one_item.add("duplicate_item", true); |
| 10025 | 162 | continue; | |
| 10026 |
6/6✓ Branch 0 taken 993860 times.
✓ Branch 1 taken 28422 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 993835 times.
✓ Branch 4 taken 25 times.
✓ Branch 5 taken 1022257 times.
|
1022282 | } else if (order->in_field_list && order->item[0]->has_subquery()) { |
| 10027 | /* | ||
| 10028 | If the order item is a subquery that is also in the field | ||
| 10029 | list, a temp table should be used to avoid evaluating the | ||
| 10030 | subquery for each row both when a) creating a sort index and | ||
| 10031 | b) getting the value. | ||
| 10032 | Example: "SELECT (SELECT ... ) as a ... GROUP BY a;" | ||
| 10033 | */ | ||
| 10034 | 25 | *simple_order = false; | |
| 10035 |
2/2✓ Branch 0 taken 1372 times.
✓ Branch 1 taken 1020885 times.
|
1022257 | } else if (order_tables & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT)) { |
| 10036 | 1372 | *simple_order = false; | |
| 10037 | } else { | ||
| 10038 |
7/8✓ Branch 0 taken 616697 times.
✓ Branch 1 taken 404188 times.
✓ Branch 2 taken 616697 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16087 times.
✓ Branch 5 taken 600610 times.
✓ Branch 6 taken 16087 times.
✓ Branch 7 taken 1004798 times.
|
1020885 | if (cond != nullptr && check_field_is_const(cond, order->item[0])) { |
| 10039 |
1/2✓ Branch 0 taken 16087 times.
✗ Branch 1 not taken.
|
16087 | trace_one_item.add("equals_constant_in_where", true); |
| 10040 | 16087 | continue; | |
| 10041 | } | ||
| 10042 |
2/2✓ Branch 0 taken 421716 times.
✓ Branch 1 taken 583082 times.
|
1004798 | if ((ref = order_tables & (not_const_tables ^ first_table))) { |
| 10043 |
4/4✓ Branch 0 taken 421534 times.
✓ Branch 1 taken 182 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 421708 times.
|
843250 | if (!(order_tables & first_table) && |
| 10044 |
3/4✓ Branch 0 taken 421534 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 421526 times.
|
421534 | only_eq_ref_tables(this, first_order, ref, &cached_eq_ref_tables, |
| 10045 | &eq_ref_tables)) { | ||
| 10046 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | trace_one_item.add("eq_ref_to_preceding_items", true); |
| 10047 | 8 | continue; | |
| 10048 | } | ||
| 10049 | 421708 | *simple_order = false; // Must do a temp table to sort | |
| 10050 | } | ||
| 10051 | } | ||
| 10052 |
2/2✓ Branch 0 taken 1006057 times.
✓ Branch 1 taken 523 times.
|
1006580 | if (change) *prev_ptr = order; // use this entry |
| 10053 | 1006580 | prev_ptr = &order->next; | |
| 10054 |
2/2✓ Branch 0 taken 1006581 times.
✓ Branch 1 taken 16634 times.
|
1023214 | } |
| 10055 |
2/2✓ Branch 0 taken 3627112 times.
✓ Branch 1 taken 675 times.
|
3627787 | if (change) *prev_ptr = nullptr; |
| 10056 |
2/2✓ Branch 0 taken 2983617 times.
✓ Branch 1 taken 644170 times.
|
3627787 | if (prev_ptr == &first_order) // Nothing to sort/group |
| 10057 | 2983617 | *simple_order = true; | |
| 10058 |
5/8✓ Branch 0 taken 3627780 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3627785 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 50 times.
✓ Branch 5 taken 3627735 times.
✓ Branch 6 taken 50 times.
✗ Branch 7 not taken.
|
3627787 | DBUG_PRINT("exit", ("simple_order: %d", (int)*simple_order)); |
| 10059 | |||
| 10060 |
1/2✓ Branch 0 taken 3627784 times.
✗ Branch 1 not taken.
|
3627785 | trace_each_item.end(); |
| 10061 |
1/2✓ Branch 0 taken 3627781 times.
✗ Branch 1 not taken.
|
3627784 | trace_simpl.add("resulting_clause_is_simple", *simple_order); |
| 10062 |
6/6✓ Branch 0 taken 5238 times.
✓ Branch 1 taken 3622548 times.
✓ Branch 2 taken 5232 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 5232 times.
✓ Branch 5 taken 3622554 times.
|
3627781 | if (trace->is_started() && change) { |
| 10063 | 5232 | String str; | |
| 10064 | 5232 | Query_block::print_order( | |
| 10065 |
1/2✓ Branch 0 taken 5232 times.
✗ Branch 1 not taken.
|
5232 | thd, &str, first_order, |
| 10066 | enum_query_type(QT_TO_SYSTEM_CHARSET | QT_SHOW_SELECT_NUMBER | | ||
| 10067 | QT_NO_DEFAULT_DB)); | ||
| 10068 |
1/2✓ Branch 0 taken 5232 times.
✗ Branch 1 not taken.
|
5232 | trace_simpl.add_utf8("resulting_clause", str.ptr(), str.length()); |
| 10069 | 5232 | } | |
| 10070 | |||
| 10071 | 3627786 | return first_order; | |
| 10072 | 3801072 | } | |
| 10073 | |||
| 10074 | /** | ||
| 10075 | Optimize conditions by | ||
| 10076 | |||
| 10077 | a) applying transitivity to build multiple equality predicates | ||
| 10078 | (MEP): if x=y and y=z the MEP x=y=z is built. | ||
| 10079 | b) apply constants where possible. If the value of x is known to be | ||
| 10080 | 42, x is replaced with a constant of value 42. By transitivity, this | ||
| 10081 | also applies to MEPs, so the MEP in a) will become 42=x=y=z. | ||
| 10082 | c) remove conditions that are always false or always true | ||
| 10083 | |||
| 10084 | @param thd Thread handler | ||
| 10085 | @param[in,out] cond WHERE or HAVING condition to optimize | ||
| 10086 | @param[out] cond_equal The built multiple equalities | ||
| 10087 | @param join_list list of join operations with join conditions | ||
| 10088 | = NULL: Called for HAVING condition | ||
| 10089 | @param[out] cond_value Not changed if cond was empty | ||
| 10090 | COND_TRUE if cond is always true | ||
| 10091 | COND_FALSE if cond is impossible | ||
| 10092 | COND_OK otherwise | ||
| 10093 | |||
| 10094 | |||
| 10095 | @returns false if success, true if error | ||
| 10096 | */ | ||
| 10097 | |||
| 10098 | 1769410 | bool optimize_cond(THD *thd, Item **cond, COND_EQUAL **cond_equal, | |
| 10099 | mem_root_deque<TABLE_LIST *> *join_list, | ||
| 10100 | Item::cond_result *cond_value) { | ||
| 10101 |
1/2✓ Branch 0 taken 1769489 times.
✗ Branch 1 not taken.
|
1769410 | DBUG_TRACE; |
| 10102 | 1769489 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 10103 | |||
| 10104 |
1/2✓ Branch 0 taken 1769462 times.
✗ Branch 1 not taken.
|
1769489 | Opt_trace_object trace_wrapper(trace); |
| 10105 |
1/2✓ Branch 0 taken 1769491 times.
✗ Branch 1 not taken.
|
1769462 | Opt_trace_object trace_cond(trace, "condition_processing"); |
| 10106 |
3/4✓ Branch 0 taken 1765525 times.
✓ Branch 1 taken 3966 times.
✓ Branch 2 taken 1769468 times.
✗ Branch 3 not taken.
|
1769491 | trace_cond.add_alnum("condition", join_list ? "WHERE" : "HAVING"); |
| 10107 |
1/2✓ Branch 0 taken 1769483 times.
✗ Branch 1 not taken.
|
1769468 | trace_cond.add("original_condition", *cond); |
| 10108 |
1/2✓ Branch 0 taken 1769482 times.
✗ Branch 1 not taken.
|
1769483 | Opt_trace_array trace_steps(trace, "steps"); |
| 10109 | |||
| 10110 | /* | ||
| 10111 | Enter this function | ||
| 10112 | a) For a WHERE condition or a query having outer join. | ||
| 10113 | b) For a HAVING condition. | ||
| 10114 | */ | ||
| 10115 |
3/4✓ Branch 0 taken 3940 times.
✓ Branch 1 taken 1765542 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3940 times.
|
1769482 | assert(*cond || join_list); |
| 10116 | |||
| 10117 | /* | ||
| 10118 | Build all multiple equality predicates and eliminate equality | ||
| 10119 | predicates that can be inferred from these multiple equalities. | ||
| 10120 | For each reference of a field included into a multiple equality | ||
| 10121 | that occurs in a function set a pointer to the multiple equality | ||
| 10122 | predicate. Substitute a constant instead of this field if the | ||
| 10123 | multiple equality contains a constant. | ||
| 10124 | This is performed for the WHERE condition and any join conditions, but | ||
| 10125 | not for the HAVING condition. | ||
| 10126 | */ | ||
| 10127 |
2/2✓ Branch 0 taken 1765518 times.
✓ Branch 1 taken 3964 times.
|
1769482 | if (join_list) { |
| 10128 |
1/2✓ Branch 0 taken 1765529 times.
✗ Branch 1 not taken.
|
1765518 | Opt_trace_object step_wrapper(trace); |
| 10129 |
1/2✓ Branch 0 taken 1765529 times.
✗ Branch 1 not taken.
|
1765529 | step_wrapper.add_alnum("transformation", "equality_propagation"); |
| 10130 | { | ||
| 10131 | Opt_trace_disable_I_S disable_trace_wrapper( | ||
| 10132 |
5/6✓ Branch 0 taken 1761562 times.
✓ Branch 1 taken 3967 times.
✓ Branch 2 taken 1757271 times.
✓ Branch 3 taken 4270 times.
✓ Branch 4 taken 1765471 times.
✗ Branch 5 not taken.
|
1765529 | trace, !(*cond && (*cond)->has_subquery())); |
| 10133 |
1/2✓ Branch 0 taken 1765518 times.
✗ Branch 1 not taken.
|
1765471 | Opt_trace_array trace_subselect(trace, "subselect_evaluation"); |
| 10134 |
3/4✓ Branch 0 taken 1765527 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1765526 times.
|
1765518 | if (build_equal_items(thd, *cond, cond, nullptr, true, join_list, |
| 10135 | cond_equal)) | ||
| 10136 | 1 | return true; | |
| 10137 |
2/4✓ Branch 0 taken 1765464 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1765482 times.
✗ Branch 3 not taken.
|
1765524 | } |
| 10138 |
1/2✓ Branch 0 taken 1765489 times.
✗ Branch 1 not taken.
|
1765482 | step_wrapper.add("resulting_condition", *cond); |
| 10139 |
2/2✓ Branch 0 taken 1765504 times.
✓ Branch 1 taken 2 times.
|
1765487 | } |
| 10140 | /* | ||
| 10141 | change field = field to field = const for each found field = const | ||
| 10142 | Note: Since we disable multi-equalities in the hypergraph optimizer for now, | ||
| 10143 | we also cannot run this optimization; it causes spurious “Impossible WHERE” | ||
| 10144 | in e.g. main.select_none. | ||
| 10145 | */ | ||
| 10146 |
4/4✓ Branch 0 taken 1765536 times.
✓ Branch 1 taken 3932 times.
✓ Branch 2 taken 1765509 times.
✓ Branch 3 taken 27 times.
|
1769468 | if (*cond && !thd->lex->using_hypergraph_optimizer) { |
| 10147 |
1/2✓ Branch 0 taken 1765511 times.
✗ Branch 1 not taken.
|
1765509 | Opt_trace_object step_wrapper(trace); |
| 10148 |
1/2✓ Branch 0 taken 1765515 times.
✗ Branch 1 not taken.
|
1765511 | step_wrapper.add_alnum("transformation", "constant_propagation"); |
| 10149 | { | ||
| 10150 | Opt_trace_disable_I_S disable_trace_wrapper(trace, | ||
| 10151 |
1/2✓ Branch 0 taken 1765508 times.
✗ Branch 1 not taken.
|
1765515 | !(*cond)->has_subquery()); |
| 10152 |
1/2✓ Branch 0 taken 1765504 times.
✗ Branch 1 not taken.
|
1765508 | Opt_trace_array trace_subselect(trace, "subselect_evaluation"); |
| 10153 |
3/4✓ Branch 0 taken 1765430 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1765429 times.
|
1765504 | if (propagate_cond_constants(thd, nullptr, *cond, *cond)) return true; |
| 10154 |
3/4✓ Branch 0 taken 1765460 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1765516 times.
✓ Branch 3 taken 9 times.
|
1765429 | } |
| 10155 |
1/2✓ Branch 0 taken 1765525 times.
✗ Branch 1 not taken.
|
1765516 | step_wrapper.add("resulting_condition", *cond); |
| 10156 |
2/2✓ Branch 0 taken 1765511 times.
✓ Branch 1 taken 2 times.
|
1765534 | } |
| 10157 | |||
| 10158 | /* | ||
| 10159 | Remove all instances of item == item | ||
| 10160 | Remove all and-levels where CONST item != CONST item | ||
| 10161 | */ | ||
| 10162 |
4/6✓ Branch 0 taken 1769488 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 1769478 times.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
1769470 | DBUG_EXECUTE("where", |
| 10163 | print_where(thd, *cond, "after const change", QT_ORDINARY);); | ||
| 10164 |
2/2✓ Branch 0 taken 1765543 times.
✓ Branch 1 taken 3945 times.
|
1769488 | if (*cond) { |
| 10165 |
1/2✓ Branch 0 taken 1765551 times.
✗ Branch 1 not taken.
|
1765543 | Opt_trace_object step_wrapper(trace); |
| 10166 |
1/2✓ Branch 0 taken 1765555 times.
✗ Branch 1 not taken.
|
1765551 | step_wrapper.add_alnum("transformation", "trivial_condition_removal"); |
| 10167 | { | ||
| 10168 | Opt_trace_disable_I_S disable_trace_wrapper(trace, | ||
| 10169 |
1/2✓ Branch 0 taken 1765553 times.
✗ Branch 1 not taken.
|
1765555 | !(*cond)->has_subquery()); |
| 10170 |
1/2✓ Branch 0 taken 1765546 times.
✗ Branch 1 not taken.
|
1765553 | Opt_trace_array trace_subselect(trace, "subselect_evaluation"); |
| 10171 |
3/4✓ Branch 0 taken 1765454 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 1765439 times.
|
1765546 | if (remove_eq_conds(thd, *cond, cond, cond_value)) return true; |
| 10172 |
4/4✓ Branch 0 taken 1765469 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 1765523 times.
✓ Branch 3 taken 18 times.
|
1765469 | } |
| 10173 |
1/2✓ Branch 0 taken 1765524 times.
✗ Branch 1 not taken.
|
1765523 | step_wrapper.add("resulting_condition", *cond); |
| 10174 |
2/2✓ Branch 0 taken 1765520 times.
✓ Branch 1 taken 14 times.
|
1765542 | } |
| 10175 |
3/4✓ Branch 0 taken 1769465 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1769459 times.
|
1769465 | if (thd->is_error()) return true; |
| 10176 | 1769459 | return false; | |
| 10177 | 1769483 | } | |
| 10178 | |||
| 10179 | /** | ||
| 10180 | Checks if a condition can be evaluated during constant folding. It can be | ||
| 10181 | evaluated if it is constant during execution and not expensive to evaluate. If | ||
| 10182 | it contains a subquery, it should not be evaluated if the option | ||
| 10183 | OPTION_NO_SUBQUERY_DURING_OPTIMIZATION is active. | ||
| 10184 | */ | ||
| 10185 | 15456165 | static bool can_evaluate_condition(THD *thd, Item *condition) { | |
| 10186 |
4/4✓ Branch 0 taken 21569 times.
✓ Branch 1 taken 15434669 times.
✓ Branch 2 taken 21527 times.
✓ Branch 3 taken 42 times.
|
15477698 | return condition->const_for_execution() && !condition->is_expensive() && |
| 10187 |
2/2✓ Branch 0 taken 21525 times.
✓ Branch 1 taken 8 times.
|
21527 | evaluate_during_optimization(condition, |
| 10188 | 15477771 | thd->lex->current_query_block()); | |
| 10189 | } | ||
| 10190 | |||
| 10191 | /** | ||
| 10192 | Calls fold_condition. If that made the condition constant for execution, | ||
| 10193 | simplify and fold again. @see fold_condition() for arguments. | ||
| 10194 | */ | ||
| 10195 | 8634525 | static bool fold_condition_exec(THD *thd, Item *cond, Item **retcond, | |
| 10196 | Item::cond_result *cond_value) { | ||
| 10197 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8634523 times.
|
8634525 | if (fold_condition(thd, cond, retcond, cond_value)) return true; |
| 10198 |
4/4✓ Branch 0 taken 8628145 times.
✓ Branch 1 taken 6378 times.
✓ Branch 2 taken 124 times.
✓ Branch 3 taken 8634476 times.
|
17262745 | if (*retcond != nullptr && |
| 10199 |
2/2✓ Branch 0 taken 124 times.
✓ Branch 1 taken 8628098 times.
|
8628145 | can_evaluate_condition(thd, *retcond)) // simplify further maybe |
| 10200 | 124 | return remove_eq_conds(thd, *retcond, retcond, cond_value); | |
| 10201 | 8634476 | return false; | |
| 10202 | } | ||
| 10203 | |||
| 10204 | /** | ||
| 10205 | Removes const and eq items. Returns the new item, or nullptr if no condition. | ||
| 10206 | |||
| 10207 | @param thd thread handler | ||
| 10208 | @param cond the condition to handle | ||
| 10209 | @param[out] retcond condition after const removal | ||
| 10210 | @param[out] cond_value resulting value of the condition | ||
| 10211 | =COND_OK condition must be evaluated (e.g. field = constant) | ||
| 10212 | =COND_TRUE always true (e.g. 1 = 1) | ||
| 10213 | =COND_FALSE always false (e.g. 1 = 2) | ||
| 10214 | |||
| 10215 | @returns false if success, true if error | ||
| 10216 | */ | ||
| 10217 | 8674370 | bool remove_eq_conds(THD *thd, Item *cond, Item **retcond, | |
| 10218 | Item::cond_result *cond_value) { | ||
| 10219 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8674434 times.
|
8674370 | assert(cond->real_item()->is_bool_func()); |
| 10220 |
2/2✓ Branch 0 taken 1846325 times.
✓ Branch 1 taken 6828108 times.
|
8674434 | if (cond->type() == Item::COND_ITEM) { |
| 10221 | 1846325 | Item_cond *const item_cond = down_cast<Item_cond *>(cond); | |
| 10222 |
1/2✓ Branch 0 taken 1846327 times.
✗ Branch 1 not taken.
|
1846327 | const bool and_level = item_cond->functype() == Item_func::COND_AND_FUNC; |
| 10223 |
1/2✓ Branch 0 taken 1846323 times.
✗ Branch 1 not taken.
|
1846327 | List_iterator<Item> li(*item_cond->argument_list()); |
| 10224 | 1846323 | bool should_fix_fields = false; | |
| 10225 | 1846323 | *cond_value = Item::COND_UNDEF; | |
| 10226 | Item *item; | ||
| 10227 |
2/2✓ Branch 0 taken 6907667 times.
✓ Branch 1 taken 1842421 times.
|
8750108 | while ((item = li++)) { |
| 10228 | Item *new_item; | ||
| 10229 | Item::cond_result tmp_cond_value; | ||
| 10230 |
2/4✓ Branch 0 taken 6907676 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6907676 times.
|
6911557 | if (remove_eq_conds(thd, item, &new_item, &tmp_cond_value)) return true; |
| 10231 | |||
| 10232 |
2/2✓ Branch 0 taken 18572 times.
✓ Branch 1 taken 6889104 times.
|
6907676 | if (new_item == nullptr) |
| 10233 |
1/2✓ Branch 0 taken 18571 times.
✗ Branch 1 not taken.
|
18572 | li.remove(); |
| 10234 |
2/2✓ Branch 0 taken 454 times.
✓ Branch 1 taken 6888650 times.
|
6889104 | else if (item != new_item) { |
| 10235 | 454 | (void)li.replace(new_item); | |
| 10236 | 454 | should_fix_fields = true; | |
| 10237 | } | ||
| 10238 |
2/2✓ Branch 0 taken 1846324 times.
✓ Branch 1 taken 5061351 times.
|
6907675 | if (*cond_value == Item::COND_UNDEF) *cond_value = tmp_cond_value; |
| 10239 |
4/5✓ Branch 0 taken 6889102 times.
✓ Branch 1 taken 13041 times.
✓ Branch 2 taken 5531 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
6907675 | switch (tmp_cond_value) { |
| 10240 | 6889102 | case Item::COND_OK: // Not true or false | |
| 10241 |
4/4✓ Branch 0 taken 1009876 times.
✓ Branch 1 taken 5879226 times.
✓ Branch 2 taken 97 times.
✓ Branch 3 taken 1009779 times.
|
6889102 | if (and_level || *cond_value == Item::COND_FALSE) |
| 10242 | 5879323 | *cond_value = tmp_cond_value; | |
| 10243 | 6889102 | break; | |
| 10244 | 13041 | case Item::COND_FALSE: | |
| 10245 |
2/2✓ Branch 0 taken 3794 times.
✓ Branch 1 taken 9247 times.
|
13041 | if (and_level) // Always false |
| 10246 | { | ||
| 10247 | 3794 | *cond_value = tmp_cond_value; | |
| 10248 | 3794 | *retcond = nullptr; | |
| 10249 | 3794 | return false; | |
| 10250 | } | ||
| 10251 | 9247 | break; | |
| 10252 | 5531 | case Item::COND_TRUE: | |
| 10253 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 5435 times.
|
5531 | if (!and_level) // Always true |
| 10254 | { | ||
| 10255 | 96 | *cond_value = tmp_cond_value; | |
| 10256 | 96 | *retcond = nullptr; | |
| 10257 | 96 | return false; | |
| 10258 | } | ||
| 10259 | 5435 | break; | |
| 10260 | ✗ | case Item::COND_UNDEF: // Impossible | |
| 10261 | ✗ | assert(false); /* purecov: deadcode */ | |
| 10262 | } | ||
| 10263 | } | ||
| 10264 |
3/4✓ Branch 0 taken 340 times.
✓ Branch 1 taken 1842081 times.
✓ Branch 2 taken 340 times.
✗ Branch 3 not taken.
|
1842421 | if (should_fix_fields) item_cond->update_used_tables(); |
| 10265 | |||
| 10266 |
4/4✓ Branch 0 taken 1842397 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 1842397 times.
|
3684818 | if (item_cond->argument_list()->elements == 0 || |
| 10267 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1842397 times.
|
1842397 | *cond_value != Item::COND_OK) { |
| 10268 | 40 | *retcond = nullptr; | |
| 10269 | 40 | return false; | |
| 10270 | } | ||
| 10271 |
2/2✓ Branch 0 taken 14454 times.
✓ Branch 1 taken 1827940 times.
|
1842397 | if (item_cond->argument_list()->elements == 1) { |
| 10272 | /* | ||
| 10273 | BUG#11765699: | ||
| 10274 | We're dealing with an AND or OR item that has only one | ||
| 10275 | argument. However, it is not an option to empty the list | ||
| 10276 | because: | ||
| 10277 | |||
| 10278 | - this function is called for either JOIN::conds or | ||
| 10279 | JOIN::having, but these point to the same condition as | ||
| 10280 | Query_block::where and Query_block::having do. | ||
| 10281 | |||
| 10282 | - The return value of remove_eq_conds() is assigned to | ||
| 10283 | JOIN::conds and JOIN::having, so emptying the list and | ||
| 10284 | returning the only remaining item "replaces" the AND or OR | ||
| 10285 | with item for the variables in JOIN. However, the return | ||
| 10286 | value is not assigned to the Query_block counterparts. Thus, | ||
| 10287 | if argument_list is emptied, Query_block forgets the item in | ||
| 10288 | argument_list()->head(). | ||
| 10289 | |||
| 10290 | item is therefore returned, but argument_list is not emptied. | ||
| 10291 | */ | ||
| 10292 | 14454 | item = item_cond->argument_list()->head(); | |
| 10293 | /* | ||
| 10294 | Consider reenabling the line below when the optimizer has been | ||
| 10295 | split into properly separated phases. | ||
| 10296 | |||
| 10297 | item_cond->argument_list()->empty(); | ||
| 10298 | */ | ||
| 10299 | 14455 | *retcond = item; | |
| 10300 | 14455 | return false; | |
| 10301 | } | ||
| 10302 |
2/2✓ Branch 0 taken 21401 times.
✓ Branch 1 taken 6806630 times.
|
6828108 | } else if (can_evaluate_condition(thd, cond)) { |
| 10303 | bool value; | ||
| 10304 |
3/4✓ Branch 0 taken 21401 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 21389 times.
|
21401 | if (eval_const_cond(thd, cond, &value)) return true; |
| 10305 |
2/2✓ Branch 0 taken 4877 times.
✓ Branch 1 taken 16512 times.
|
21389 | *cond_value = value ? Item::COND_TRUE : Item::COND_FALSE; |
| 10306 | 21389 | *retcond = nullptr; | |
| 10307 | 21389 | return false; | |
| 10308 | } else { // Boolean compare function | ||
| 10309 | 6806630 | *cond_value = cond->eq_cmp_result(); | |
| 10310 |
2/2✓ Branch 0 taken 5586908 times.
✓ Branch 1 taken 1219783 times.
|
6806691 | if (*cond_value == Item::COND_OK) { |
| 10311 | 5586908 | return fold_condition_exec(thd, cond, retcond, cond_value); | |
| 10312 | } | ||
| 10313 | 1219783 | Item *left_item = down_cast<Item_func *>(cond)->arguments()[0]; | |
| 10314 | 1219791 | Item *right_item = down_cast<Item_func *>(cond)->arguments()[1]; | |
| 10315 |
6/6✓ Branch 0 taken 68 times.
✓ Branch 1 taken 1219715 times.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 67 times.
✓ Branch 5 taken 1219716 times.
|
1219793 | if (left_item->eq(right_item, true) && !cond->is_non_deterministic()) { |
| 10316 | /* | ||
| 10317 | Two identical items are being compared: | ||
| 10318 | 1) If the items are not nullable, return result from eq_cmp_result(), | ||
| 10319 | that is, we can short circuit because result is statically always | ||
| 10320 | known to be true or false, depending on which operator we are | ||
| 10321 | dealing with. If the operator allows equality, *cond_value is | ||
| 10322 | Item::COND_TRUE (a non-null value is always equal to itself), else | ||
| 10323 | Item::COND_FALSE (a non-null value is never unequal to itself). | ||
| 10324 | 2) If the items are nullable and the result from eq_cmp_result() is | ||
| 10325 | false, result is always false, that is, the operator doesn't | ||
| 10326 | allow for equality, the result is always false: Any non-null | ||
| 10327 | value cannot obviously be unequal to itself, and any NULL value | ||
| 10328 | would yield an undefined result (e.g. NULL < NULL | ||
| 10329 | is undefined), and hence Item::COND_FALSE in this context is the | ||
| 10330 | effective result. | ||
| 10331 | (Call order ensures test is not applied to conditions with explicit | ||
| 10332 | truth value test) | ||
| 10333 | 3) If the <=> operator is used, result is always true because | ||
| 10334 | NULL = NULL is true for this operator | ||
| 10335 | */ | ||
| 10336 |
6/6✓ Branch 0 taken 53 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 46 times.
✓ Branch 5 taken 21 times.
|
93 | if (!left_item->is_nullable() || *cond_value == Item::COND_FALSE || |
| 10337 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
|
26 | down_cast<Item_func *>(cond)->functype() == Item_func::EQUAL_FUNC) { |
| 10338 | 46 | *retcond = nullptr; | |
| 10339 | 46 | return false; | |
| 10340 | } | ||
| 10341 | } | ||
| 10342 | } | ||
| 10343 | 3047677 | return fold_condition_exec(thd, cond, retcond, cond_value); | |
| 10344 | } | ||
| 10345 | |||
| 10346 | /** | ||
| 10347 | Check if GROUP BY/DISTINCT can be optimized away because the set is | ||
| 10348 | already known to be distinct. | ||
| 10349 | |||
| 10350 | Used in removing the GROUP BY/DISTINCT of the following types of | ||
| 10351 | statements: | ||
| 10352 | @code | ||
| 10353 | SELECT [DISTINCT] <unique_key_cols>... FROM <single_table_ref> | ||
| 10354 | [GROUP BY <unique_key_cols>,...] | ||
| 10355 | @endcode | ||
| 10356 | |||
| 10357 | If (a,b,c is distinct) | ||
| 10358 | then <any combination of a,b,c>,{whatever} is also distinct | ||
| 10359 | |||
| 10360 | This function checks if all the key parts of any of the unique keys | ||
| 10361 | of the table are referenced by a list : either the select list | ||
| 10362 | through find_field_in_item_list or GROUP BY list through | ||
| 10363 | find_field_in_order_list. | ||
| 10364 | If the above holds and the key parts cannot contain NULLs then we | ||
| 10365 | can safely remove the GROUP BY/DISTINCT, | ||
| 10366 | as no result set can be more distinct than an unique key. | ||
| 10367 | |||
| 10368 | @param tab The join table to operate on. | ||
| 10369 | @param find_func function to iterate over the list and search | ||
| 10370 | for a field | ||
| 10371 | @param data data that's passed through to to find_func | ||
| 10372 | |||
| 10373 | @retval | ||
| 10374 | 1 found | ||
| 10375 | @retval | ||
| 10376 | 0 not found. | ||
| 10377 | |||
| 10378 | @note | ||
| 10379 | The function assumes that make_outerjoin_info() has been called in | ||
| 10380 | order for the check for outer tables to work. | ||
| 10381 | */ | ||
| 10382 | |||
| 10383 | 3929 | static bool list_contains_unique_index(JOIN_TAB *tab, | |
| 10384 | bool (*find_func)(Field *, void *), | ||
| 10385 | void *data) { | ||
| 10386 | 3929 | TABLE *table = tab->table(); | |
| 10387 | |||
| 10388 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3917 times.
|
3929 | if (tab->is_inner_table_of_outer_join()) return false; |
| 10389 |
2/2✓ Branch 0 taken 2442 times.
✓ Branch 1 taken 3575 times.
|
6017 | for (uint keynr = 0; keynr < table->s->keys; keynr++) { |
| 10390 |
2/2✓ Branch 0 taken 1514 times.
✓ Branch 1 taken 928 times.
|
2442 | if (keynr == table->s->primary_key || |
| 10391 |
2/2✓ Branch 0 taken 635 times.
✓ Branch 1 taken 879 times.
|
1514 | (table->key_info[keynr].flags & HA_NOSAME)) { |
| 10392 | 1563 | KEY *keyinfo = table->key_info + keynr; | |
| 10393 | KEY_PART_INFO *key_part, *key_part_end; | ||
| 10394 | |||
| 10395 | 433 | for (key_part = keyinfo->key_part, | |
| 10396 | 1563 | key_part_end = key_part + keyinfo->user_defined_key_parts; | |
| 10397 |
2/2✓ Branch 0 taken 1654 times.
✓ Branch 1 taken 342 times.
|
1996 | key_part < key_part_end; key_part++) { |
| 10398 |
6/6✓ Branch 0 taken 1245 times.
✓ Branch 1 taken 409 times.
✓ Branch 2 taken 812 times.
✓ Branch 3 taken 433 times.
✓ Branch 4 taken 1221 times.
✓ Branch 5 taken 433 times.
|
1654 | if (key_part->field->is_nullable() || !find_func(key_part->field, data)) |
| 10399 | 1221 | break; | |
| 10400 | } | ||
| 10401 |
2/2✓ Branch 0 taken 342 times.
✓ Branch 1 taken 1221 times.
|
1563 | if (key_part == key_part_end) return true; |
| 10402 | } | ||
| 10403 | } | ||
| 10404 | 3575 | return false; | |
| 10405 | } | ||
| 10406 | |||
| 10407 | /** | ||
| 10408 | Helper function for list_contains_unique_index. | ||
| 10409 | Find a field reference in a list of ORDER structures. | ||
| 10410 | Finds a direct reference of the Field in the list. | ||
| 10411 | |||
| 10412 | @param field The field to search for. | ||
| 10413 | @param data ORDER *.The list to search in | ||
| 10414 | |||
| 10415 | @retval | ||
| 10416 | 1 found | ||
| 10417 | @retval | ||
| 10418 | 0 not found. | ||
| 10419 | */ | ||
| 10420 | |||
| 10421 | 353 | static bool find_field_in_order_list(Field *field, void *data) { | |
| 10422 | 353 | ORDER *group = (ORDER *)data; | |
| 10423 | 353 | bool part_found = false; | |
| 10424 |
2/2✓ Branch 0 taken 408 times.
✓ Branch 1 taken 141 times.
|
549 | for (ORDER *tmp_group = group; tmp_group; tmp_group = tmp_group->next) { |
| 10425 | 408 | const Item *item = (*tmp_group->item)->real_item(); | |
| 10426 |
4/4✓ Branch 0 taken 338 times.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 212 times.
✓ Branch 3 taken 196 times.
|
746 | if (item->type() == Item::FIELD_ITEM && |
| 10427 |
2/2✓ Branch 0 taken 212 times.
✓ Branch 1 taken 126 times.
|
338 | down_cast<const Item_field *>(item)->field->eq(field)) { |
| 10428 | 212 | part_found = true; | |
| 10429 | 212 | break; | |
| 10430 | } | ||
| 10431 | } | ||
| 10432 | 353 | return part_found; | |
| 10433 | } | ||
| 10434 | |||
| 10435 | /** | ||
| 10436 | Helper function for list_contains_unique_index. | ||
| 10437 | Find a field reference in a dynamic list of Items. | ||
| 10438 | Finds a direct reference of the Field in the list. | ||
| 10439 | |||
| 10440 | @param[in] field The field to search for. | ||
| 10441 | @param[in] data List<Item> *.The list to search in | ||
| 10442 | |||
| 10443 | @retval | ||
| 10444 | 1 found | ||
| 10445 | @retval | ||
| 10446 | 0 not found. | ||
| 10447 | */ | ||
| 10448 | |||
| 10449 | 892 | static bool find_field_in_item_list(Field *field, void *data) { | |
| 10450 | 892 | mem_root_deque<Item *> *fields = | |
| 10451 | reinterpret_cast<mem_root_deque<Item *> *>(data); | ||
| 10452 | 892 | bool part_found = false; | |
| 10453 | |||
| 10454 |
8/14✓ Branch 0 taken 892 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 892 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 892 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1004 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 783 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1675 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1004 times.
✓ Branch 13 taken 671 times.
|
1675 | for (const Item *item : VisibleFields(*fields)) { |
| 10455 |
5/6✓ Branch 0 taken 1004 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 762 times.
✓ Branch 3 taken 242 times.
✓ Branch 4 taken 221 times.
✓ Branch 5 taken 783 times.
|
1766 | if (item->type() == Item::FIELD_ITEM && |
| 10456 |
3/4✓ Branch 0 taken 762 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 221 times.
✓ Branch 3 taken 541 times.
|
762 | down_cast<const Item_field *>(item)->field->eq(field)) { |
| 10457 | 221 | part_found = true; | |
| 10458 | 221 | break; | |
| 10459 | } | ||
| 10460 | } | ||
| 10461 | 892 | return part_found; | |
| 10462 | } | ||
| 10463 | |||
| 10464 | 2948 | ORDER *create_order_from_distinct(THD *thd, Ref_item_array ref_item_array, | |
| 10465 | ORDER *order_list, | ||
| 10466 | mem_root_deque<Item *> *fields, | ||
| 10467 | bool skip_aggregates, | ||
| 10468 | bool convert_bit_fields_to_long, | ||
| 10469 | bool *all_order_by_fields_used) { | ||
| 10470 | 2948 | ORDER *group = nullptr, **prev = &group; | |
| 10471 | |||
| 10472 | 2948 | *all_order_by_fields_used = true; | |
| 10473 | |||
| 10474 |
2/2✓ Branch 0 taken 335 times.
✓ Branch 1 taken 2948 times.
|
3283 | for (ORDER *order = order_list; order; order = order->next) { |
| 10475 |
2/2✓ Branch 0 taken 265 times.
✓ Branch 1 taken 70 times.
|
335 | if (order->in_field_list) { |
| 10476 |
1/2✓ Branch 0 taken 265 times.
✗ Branch 1 not taken.
|
265 | ORDER *ord = (ORDER *)thd->memdup((char *)order, sizeof(ORDER)); |
| 10477 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 265 times.
|
265 | if (!ord) return nullptr; |
| 10478 | 265 | *prev = ord; | |
| 10479 | 265 | prev = &ord->next; | |
| 10480 | 265 | (*ord->item)->marker = Item::MARKER_DISTINCT_GROUP; | |
| 10481 | } else | ||
| 10482 | 70 | *all_order_by_fields_used = false; | |
| 10483 | } | ||
| 10484 | |||
| 10485 |
1/2✓ Branch 0 taken 2948 times.
✗ Branch 1 not taken.
|
2948 | Mem_root_array<std::pair<Item *, ORDER *>> bit_fields_to_add(thd->mem_root); |
| 10486 | |||
| 10487 |
8/14✓ Branch 0 taken 2948 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2948 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2948 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4282 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4282 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7230 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4282 times.
✓ Branch 13 taken 2948 times.
|
7230 | for (Item *&item : VisibleFields(*fields)) { |
| 10488 |
8/10✓ Branch 0 taken 4282 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4204 times.
✓ Branch 3 taken 78 times.
✓ Branch 4 taken 4042 times.
✓ Branch 5 taken 162 times.
✓ Branch 6 taken 4042 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 343 times.
✓ Branch 9 taken 3939 times.
|
8486 | if (!item->const_item() && (!skip_aggregates || !item->has_aggregation()) && |
| 10489 |
2/2✓ Branch 0 taken 3939 times.
✓ Branch 1 taken 265 times.
|
4204 | item->marker != Item::MARKER_DISTINCT_GROUP) { |
| 10490 | /* | ||
| 10491 | Don't put duplicate columns from the SELECT list into the | ||
| 10492 | GROUP BY list. | ||
| 10493 | */ | ||
| 10494 | ORDER *ord_iter; | ||
| 10495 |
2/2✓ Branch 0 taken 3072 times.
✓ Branch 1 taken 3930 times.
|
7002 | for (ord_iter = group; ord_iter; ord_iter = ord_iter->next) |
| 10496 |
3/4✓ Branch 0 taken 3072 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 3063 times.
|
3072 | if ((*ord_iter->item)->eq(item, true)) goto next_item; |
| 10497 | |||
| 10498 |
1/2✓ Branch 0 taken 3930 times.
✗ Branch 1 not taken.
|
3930 | ORDER *ord = (ORDER *)thd->mem_calloc(sizeof(ORDER)); |
| 10499 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3930 times.
|
3930 | if (!ord) return nullptr; |
| 10500 | |||
| 10501 |
3/4✓ Branch 0 taken 3930 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3380 times.
|
7316 | if (item->type() == Item::FIELD_ITEM && |
| 10502 |
6/6✓ Branch 0 taken 3386 times.
✓ Branch 1 taken 544 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 3925 times.
|
7316 | item->data_type() == MYSQL_TYPE_BIT && convert_bit_fields_to_long) { |
| 10503 | /* | ||
| 10504 | Because HEAP tables can't index BIT fields we need to use an | ||
| 10505 | additional hidden field for grouping because later it will be | ||
| 10506 | converted to a LONG field. Original field will remain of the | ||
| 10507 | BIT type and will be returned to a client. | ||
| 10508 | @note setup_ref_array() needs to account for the extra space. | ||
| 10509 | @note We need to defer the actual adding to after the loop, | ||
| 10510 | or we will invalidate the iterator to “fields”. | ||
| 10511 | */ | ||
| 10512 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | Item_field *new_item = new Item_field(thd, (Item_field *)item); |
| 10513 | 5 | ord->item = &item; // Temporary; for the duplicate check above. | |
| 10514 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | bit_fields_to_add.push_back(std::make_pair(new_item, ord)); |
| 10515 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 3877 times.
|
3925 | } else if (ref_item_array.is_null()) { |
| 10516 | // No slices are in use, so just use the field from the list. | ||
| 10517 | 48 | ord->item = &item; | |
| 10518 | } else { | ||
| 10519 | /* | ||
| 10520 | We have here only visible fields, so we can use simple indexing | ||
| 10521 | of ref_item_array (order in the array and in the list are same) | ||
| 10522 | */ | ||
| 10523 | 3877 | ord->item = &ref_item_array[0]; | |
| 10524 | } | ||
| 10525 | 3930 | ord->direction = ORDER_ASC; | |
| 10526 | 3930 | *prev = ord; | |
| 10527 | 3930 | prev = &ord->next; | |
| 10528 | } | ||
| 10529 | 343 | next_item: | |
| 10530 |
2/2✓ Branch 0 taken 4234 times.
✓ Branch 1 taken 48 times.
|
4282 | if (!ref_item_array.is_null()) { |
| 10531 | 4234 | ref_item_array.pop_front(); | |
| 10532 | } | ||
| 10533 | } | ||
| 10534 |
3/4✓ Branch 0 taken 2948 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 2948 times.
|
2953 | for (const auto &item_and_order : bit_fields_to_add) { |
| 10535 | 10 | item_and_order.second->item = | |
| 10536 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | thd->lex->current_query_block()->add_hidden_item(item_and_order.first); |
| 10537 | 5 | thd->lex->current_query_block()->hidden_items_from_optimization++; | |
| 10538 | } | ||
| 10539 | 2948 | *prev = nullptr; | |
| 10540 | 2948 | return group; | |
| 10541 | 2948 | } | |
| 10542 | |||
| 10543 | /** | ||
| 10544 | Return table number if there is only one table in sort order | ||
| 10545 | and group and order is compatible, else return 0. | ||
| 10546 | */ | ||
| 10547 | |||
| 10548 | 1912154 | static TABLE *get_sort_by_table(ORDER *a, ORDER *b, TABLE_LIST *tables) { | |
| 10549 |
1/2✓ Branch 0 taken 1912172 times.
✗ Branch 1 not taken.
|
1912154 | DBUG_TRACE; |
| 10550 | 1912172 | table_map map = (table_map)0; | |
| 10551 | |||
| 10552 |
2/2✓ Branch 0 taken 1273144 times.
✓ Branch 1 taken 639028 times.
|
1912172 | if (!a) |
| 10553 | 1273144 | a = b; // Only one need to be given | |
| 10554 |
2/2✓ Branch 0 taken 635597 times.
✓ Branch 1 taken 3431 times.
|
639028 | else if (!b) |
| 10555 | 635597 | b = a; | |
| 10556 | |||
| 10557 |
4/4✓ Branch 0 taken 1021753 times.
✓ Branch 1 taken 1911569 times.
✓ Branch 2 taken 1021724 times.
✓ Branch 3 taken 29 times.
|
2933322 | for (; a && b; a = a->next, b = b->next) { |
| 10558 |
3/4✓ Branch 0 taken 1021723 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 573 times.
✓ Branch 3 taken 1021150 times.
|
1021724 | if (!(*a->item)->eq(*b->item, true)) return nullptr; |
| 10559 |
1/2✓ Branch 0 taken 1021150 times.
✗ Branch 1 not taken.
|
1021150 | map |= a->item[0]->used_tables(); |
| 10560 | } | ||
| 10561 | 1911598 | map &= ~INNER_TABLE_BIT; | |
| 10562 |
4/4✓ Branch 0 taken 645258 times.
✓ Branch 1 taken 1266340 times.
✓ Branch 2 taken 1372 times.
✓ Branch 3 taken 643886 times.
|
1911598 | if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT))) return nullptr; |
| 10563 | |||
| 10564 |
2/2✓ Branch 0 taken 29676 times.
✓ Branch 1 taken 643886 times.
|
673562 | for (; !(map & tables->map()); tables = tables->next_leaf) |
| 10565 | ; | ||
| 10566 |
2/2✓ Branch 0 taken 149002 times.
✓ Branch 1 taken 494884 times.
|
643886 | if (map != tables->map()) return nullptr; // More than one table |
| 10567 |
5/8✓ Branch 0 taken 494884 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 494884 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 494883 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
494884 | DBUG_PRINT("exit", ("sort by table: %d", tables->tableno())); |
| 10568 | 494884 | return tables->table; | |
| 10569 | 1912171 | } | |
| 10570 | |||
| 10571 | /** | ||
| 10572 | Update some values in keyuse for faster choose_table_order() loop. | ||
| 10573 | |||
| 10574 | @todo Check if this is the real meaning of ref_table_rows. | ||
| 10575 | */ | ||
| 10576 | |||
| 10577 | 1815655 | void JOIN::optimize_keyuse() { | |
| 10578 |
2/2✓ Branch 0 taken 5076002 times.
✓ Branch 1 taken 1815668 times.
|
6891657 | for (size_t ix = 0; ix < keyuse_array.size(); ++ix) { |
| 10579 | 5076002 | Key_use *keyuse = &keyuse_array.at(ix); | |
| 10580 | table_map map; | ||
| 10581 | /* | ||
| 10582 | If we find a ref, assume this table matches a proportional | ||
| 10583 | part of this table. | ||
| 10584 | For example 100 records matching a table with 5000 records | ||
| 10585 | gives 5000/100 = 50 records per key | ||
| 10586 | Constant tables are ignored. | ||
| 10587 | To avoid bad matches, we don't make ref_table_rows less than 100. | ||
| 10588 | */ | ||
| 10589 | 5076011 | keyuse->ref_table_rows = ~(ha_rows)0; // If no ref | |
| 10590 | 5076011 | if (keyuse->used_tables & | |
| 10591 |
2/2✓ Branch 0 taken 4180595 times.
✓ Branch 1 taken 895416 times.
|
5076011 | (map = keyuse->used_tables & ~(const_table_map | PSEUDO_TABLE_BITS))) { |
| 10592 | uint tableno; | ||
| 10593 |
2/2✓ Branch 0 taken 15740268 times.
✓ Branch 1 taken 4180595 times.
|
19920863 | for (tableno = 0; !(map & 1); map >>= 1, tableno++) { |
| 10594 | } | ||
| 10595 |
2/2✓ Branch 0 taken 4179701 times.
✓ Branch 1 taken 894 times.
|
4180595 | if (map == 1) // Only one table |
| 10596 | { | ||
| 10597 | 4179701 | TABLE *tmp_table = join_tab[tableno].table(); | |
| 10598 | |||
| 10599 | 4179692 | keyuse->ref_table_rows = | |
| 10600 | 4179698 | max<ha_rows>(tmp_table->file->stats.records, 100); | |
| 10601 | } | ||
| 10602 | } | ||
| 10603 | /* | ||
| 10604 | Outer reference (external field) is constant for single executing | ||
| 10605 | of subquery | ||
| 10606 | */ | ||
| 10607 |
2/2✓ Branch 0 taken 1710 times.
✓ Branch 1 taken 5074292 times.
|
5076002 | if (keyuse->used_tables == OUTER_REF_TABLE_BIT) keyuse->ref_table_rows = 1; |
| 10608 | } | ||
| 10609 | 1815668 | } | |
| 10610 | |||
| 10611 | /** | ||
| 10612 | Function sets FT hints, initializes FT handlers | ||
| 10613 | and checks if FT index can be used as covered. | ||
| 10614 | */ | ||
| 10615 | |||
| 10616 | 2293 | bool JOIN::optimize_fts_query() { | |
| 10617 |
3/6✓ Branch 0 taken 2293 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2293 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2293 times.
✗ Branch 5 not taken.
|
2293 | ASSERT_BEST_REF_IN_JOIN_ORDER(this); |
| 10618 | |||
| 10619 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2293 times.
|
2293 | assert(query_block->has_ft_funcs()); |
| 10620 | |||
| 10621 | // Only used by the old optimizer. | ||
| 10622 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2293 times.
|
2293 | assert(!thd->lex->using_hypergraph_optimizer); |
| 10623 | |||
| 10624 |
2/2✓ Branch 0 taken 4850 times.
✓ Branch 1 taken 2293 times.
|
7143 | for (uint i = const_tables; i < tables; i++) { |
| 10625 | 4850 | JOIN_TAB *tab = best_ref[i]; | |
| 10626 |
2/2✓ Branch 0 taken 2716 times.
✓ Branch 1 taken 2134 times.
|
4850 | if (tab->type() != JT_FT) continue; |
| 10627 | |||
| 10628 | Item_func_match *ifm; | ||
| 10629 | Item_func_match *ft_func = | ||
| 10630 | 2134 | down_cast<Item_func_match *>(tab->position()->key->val); | |
| 10631 |
1/2✓ Branch 0 taken 2134 times.
✗ Branch 1 not taken.
|
2134 | List_iterator<Item_func_match> li(*(query_block->ftfunc_list)); |
| 10632 | |||
| 10633 |
2/2✓ Branch 0 taken 2266 times.
✓ Branch 1 taken 2134 times.
|
4400 | while ((ifm = li++)) { |
| 10634 |
6/6✓ Branch 0 taken 2231 times.
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 2156 times.
✓ Branch 4 taken 110 times.
✓ Branch 5 taken 2156 times.
|
2266 | if (!(ifm->used_tables() & tab->table_ref->map()) || ifm->master) |
| 10635 | 110 | continue; | |
| 10636 | |||
| 10637 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 2134 times.
|
2156 | if (ifm != ft_func) { |
| 10638 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 20 times.
|
22 | if (ifm->can_skip_ranking()) |
| 10639 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | ifm->set_hints(this, FT_NO_RANKING, HA_POS_ERROR, false); |
| 10640 | } | ||
| 10641 | } | ||
| 10642 | |||
| 10643 | /* | ||
| 10644 | Check if internal sorting is needed. FT_SORTED flag is set | ||
| 10645 | if no ORDER BY clause or ORDER BY MATCH function is the same | ||
| 10646 | as the function that is used for FT index and FT table is | ||
| 10647 | the first non-constant table in the JOIN. | ||
| 10648 | */ | ||
| 10649 |
8/8✓ Branch 0 taken 2112 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 949 times.
✓ Branch 3 taken 1163 times.
✓ Branch 4 taken 59 times.
✓ Branch 5 taken 890 times.
✓ Branch 6 taken 907 times.
✓ Branch 7 taken 1227 times.
|
3142 | if (i == const_tables && !(ft_func->get_hints()->get_flags() & FT_BOOL) && |
| 10650 |
3/4✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 42 times.
|
1008 | (order.empty() || ft_func == test_if_ft_index_order(order.order))) |
| 10651 |
1/2✓ Branch 0 taken 907 times.
✗ Branch 1 not taken.
|
907 | ft_func->set_hints(this, FT_SORTED, m_select_limit, false); |
| 10652 | |||
| 10653 | /* | ||
| 10654 | Check if ranking is not needed. FT_NO_RANKING flag is set if | ||
| 10655 | MATCH function is used only in WHERE condition and MATCH | ||
| 10656 | function is not part of an expression. | ||
| 10657 | */ | ||
| 10658 |
2/2✓ Branch 0 taken 1261 times.
✓ Branch 1 taken 873 times.
|
2134 | if (ft_func->can_skip_ranking()) |
| 10659 |
3/4✓ Branch 0 taken 1221 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 1261 times.
✗ Branch 3 not taken.
|
1261 | ft_func->set_hints(this, FT_NO_RANKING, |
| 10660 | 1261 | order.empty() ? m_select_limit : HA_POS_ERROR, false); | |
| 10661 | } | ||
| 10662 | |||
| 10663 | 2293 | return init_ftfuncs(thd, query_block); | |
| 10664 | } | ||
| 10665 | |||
| 10666 | /** | ||
| 10667 | Check if FTS index only access is possible. | ||
| 10668 | |||
| 10669 | @param tab pointer to JOIN_TAB structure. | ||
| 10670 | |||
| 10671 | @return true if index only access is possible, | ||
| 10672 | false otherwise. | ||
| 10673 | */ | ||
| 10674 | |||
| 10675 | 2141 | bool JOIN::fts_index_access(JOIN_TAB *tab) { | |
| 10676 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2141 times.
|
2141 | assert(tab->type() == JT_FT); |
| 10677 | 2141 | TABLE *table = tab->table(); | |
| 10678 | |||
| 10679 | // Give up if index-only access has already been disabled on this table. | ||
| 10680 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2141 times.
|
2141 | if (table->no_keyread) { |
| 10681 | ✗ | return false; | |
| 10682 | } | ||
| 10683 | |||
| 10684 |
2/2✓ Branch 0 taken 198 times.
✓ Branch 1 taken 1943 times.
|
2141 | if ((table->file->ha_table_flags() & HA_CAN_FULLTEXT_EXT) == 0) |
| 10685 | 198 | return false; // Optimizations requires extended FTS support by table | |
| 10686 | // engine | ||
| 10687 | |||
| 10688 | /* | ||
| 10689 | This optimization does not work with filesort nor GROUP BY | ||
| 10690 | */ | ||
| 10691 |
4/4✓ Branch 0 taken 1937 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 1883 times.
|
3880 | if (grouped || |
| 10692 |
4/4✓ Branch 0 taken 84 times.
✓ Branch 1 taken 1853 times.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 30 times.
|
1937 | (!order.empty() && m_ordered_index_usage != ORDERED_INDEX_ORDER_BY)) |
| 10693 | 60 | return false; | |
| 10694 | |||
| 10695 | /* | ||
| 10696 | Check whether the FTS result is covering. If only document id | ||
| 10697 | and rank is needed, there is no need to access table rows. | ||
| 10698 | */ | ||
| 10699 |
2/2✓ Branch 0 taken 1963 times.
✓ Branch 1 taken 57 times.
|
2020 | for (uint i = bitmap_get_first_set(table->read_set); i < table->s->fields; |
| 10700 | 137 | i = bitmap_get_next_set(table->read_set, i)) { | |
| 10701 |
4/4✓ Branch 0 taken 137 times.
✓ Branch 1 taken 1826 times.
✓ Branch 2 taken 1826 times.
✓ Branch 3 taken 137 times.
|
2100 | if (table->field[i] != table->fts_doc_id_field || |
| 10702 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 137 times.
|
137 | !tab->ft_func()->docid_in_result()) |
| 10703 | 1826 | return false; | |
| 10704 | } | ||
| 10705 | |||
| 10706 | 57 | return true; | |
| 10707 | } | ||
| 10708 | |||
| 10709 | /** | ||
| 10710 | For {semijoin,subquery} materialization: calculates various cost | ||
| 10711 | information, based on a plan in join->best_positions covering the | ||
| 10712 | to-be-materialized query block and only this. | ||
| 10713 | |||
| 10714 | @param join JOIN where plan can be found | ||
| 10715 | @param sj_nest sj materialization nest (NULL if subquery materialization) | ||
| 10716 | @param n_tables number of to-be-materialized tables | ||
| 10717 | @param[out] sjm where computed costs will be stored | ||
| 10718 | |||
| 10719 | @note that this function modifies join->map2table, which has to be filled | ||
| 10720 | correctly later. | ||
| 10721 | */ | ||
| 10722 | 2635 | static void calculate_materialization_costs(JOIN *join, TABLE_LIST *sj_nest, | |
| 10723 | uint n_tables, | ||
| 10724 | Semijoin_mat_optimize *sjm) { | ||
| 10725 | double mat_cost; // Estimated cost of materialization | ||
| 10726 | double mat_rowcount; // Estimated row count before duplicate removal | ||
| 10727 | double distinct_rowcount; // Estimated rowcount after duplicate removal | ||
| 10728 | mem_root_deque<Item *> *inner_expr_list; | ||
| 10729 | |||
| 10730 |
2/2✓ Branch 0 taken 2333 times.
✓ Branch 1 taken 302 times.
|
2635 | if (sj_nest) { |
| 10731 | /* | ||
| 10732 | get_partial_join_cost() assumes a regular join, which is correct when | ||
| 10733 | we optimize a sj-materialization nest (always executed as regular | ||
| 10734 | join). | ||
| 10735 | */ | ||
| 10736 |
1/2✓ Branch 0 taken 2333 times.
✗ Branch 1 not taken.
|
2333 | get_partial_join_cost(join, n_tables, &mat_cost, &mat_rowcount); |
| 10737 | 2333 | n_tables += join->const_tables; | |
| 10738 | 2333 | inner_expr_list = &sj_nest->nested_join->sj_inner_exprs; | |
| 10739 | } else { | ||
| 10740 | 302 | mat_cost = join->best_read; | |
| 10741 | 302 | mat_rowcount = static_cast<double>(join->best_rowcount); | |
| 10742 | 302 | inner_expr_list = &join->query_block->fields; | |
| 10743 | } | ||
| 10744 | |||
| 10745 | /* | ||
| 10746 | Adjust output cardinality estimates. If the subquery has form | ||
| 10747 | |||
| 10748 | ... oe IN (SELECT t1.colX, t2.colY, func(X,Y,Z) ) | ||
| 10749 | |||
| 10750 | then the number of distinct output record combinations has an | ||
| 10751 | upper bound of product of number of records matching the tables | ||
| 10752 | that are used by the SELECT clause. | ||
| 10753 | TODO: | ||
| 10754 | We can get a more precise estimate if we | ||
| 10755 | - use rec_per_key cardinality estimates. For simple cases like | ||
| 10756 | "oe IN (SELECT t.key ...)" it is trivial. | ||
| 10757 | - Functional dependencies between the tables in the semi-join | ||
| 10758 | nest (the payoff is probably less here?) | ||
| 10759 | */ | ||
| 10760 | { | ||
| 10761 |
2/2✓ Branch 0 taken 9289 times.
✓ Branch 1 taken 2635 times.
|
11924 | for (uint i = 0; i < n_tables; i++) { |
| 10762 | 9289 | JOIN_TAB *const tab = join->best_positions[i].table; | |
| 10763 | 9289 | join->map2table[tab->table_ref->tableno()] = tab; | |
| 10764 | } | ||
| 10765 | 2635 | table_map map = 0; | |
| 10766 |
7/12✓ Branch 0 taken 2635 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2635 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2635 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2706 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5341 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2706 times.
✓ Branch 11 taken 2635 times.
|
5341 | for (Item *item : VisibleFields(*inner_expr_list)) { |
| 10767 |
2/4✓ Branch 0 taken 2706 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2706 times.
✗ Branch 3 not taken.
|
2706 | map |= item->used_tables(); |
| 10768 | } | ||
| 10769 | 2635 | map &= ~PSEUDO_TABLE_BITS; | |
| 10770 | 2635 | Table_map_iterator tm_it(map); | |
| 10771 | int tableno; | ||
| 10772 | 2635 | double rows = 1.0; | |
| 10773 |
2/2✓ Branch 0 taken 3270 times.
✓ Branch 1 taken 2635 times.
|
5905 | while ((tableno = tm_it.next_bit()) != Table_map_iterator::BITMAP_END) |
| 10774 | 3270 | rows *= join->map2table[tableno]->table()->quick_condition_rows; | |
| 10775 | 2635 | distinct_rowcount = min(mat_rowcount, rows); | |
| 10776 | } | ||
| 10777 | /* | ||
| 10778 | Calculate temporary table parameters and usage costs | ||
| 10779 | */ | ||
| 10780 |
1/2✓ Branch 0 taken 2635 times.
✗ Branch 1 not taken.
|
2635 | const uint rowlen = get_tmp_table_rec_length(*inner_expr_list); |
| 10781 | |||
| 10782 |
1/2✓ Branch 0 taken 2635 times.
✗ Branch 1 not taken.
|
2635 | const Cost_model_server *cost_model = join->cost_model(); |
| 10783 | |||
| 10784 | Cost_model_server::enum_tmptable_type tmp_table_type; | ||
| 10785 |
2/2✓ Branch 0 taken 2629 times.
✓ Branch 1 taken 6 times.
|
2635 | if (rowlen * distinct_rowcount < join->thd->variables.max_heap_table_size) |
| 10786 | 2629 | tmp_table_type = Cost_model_server::MEMORY_TMPTABLE; | |
| 10787 | else | ||
| 10788 | 6 | tmp_table_type = Cost_model_server::DISK_TMPTABLE; | |
| 10789 | |||
| 10790 | /* | ||
| 10791 | Let materialization cost include the cost to create the temporary | ||
| 10792 | table and write the rows into it: | ||
| 10793 | */ | ||
| 10794 | 2635 | mat_cost += cost_model->tmptable_create_cost(tmp_table_type); | |
| 10795 | 2635 | mat_cost += | |
| 10796 | 2635 | cost_model->tmptable_readwrite_cost(tmp_table_type, mat_rowcount, 0.0); | |
| 10797 | |||
| 10798 | 2635 | sjm->materialization_cost.reset(); | |
| 10799 | 2635 | sjm->materialization_cost.add_io(mat_cost); | |
| 10800 | |||
| 10801 | 2635 | sjm->expected_rowcount = distinct_rowcount; | |
| 10802 | |||
| 10803 | /* | ||
| 10804 | Set the cost to do a full scan of the temptable (will need this to | ||
| 10805 | consider doing sjm-scan): | ||
| 10806 | */ | ||
| 10807 | 2635 | sjm->scan_cost.reset(); | |
| 10808 |
2/2✓ Branch 0 taken 2617 times.
✓ Branch 1 taken 18 times.
|
2635 | if (distinct_rowcount > 0.0) { |
| 10809 | 2617 | const double scan_cost = cost_model->tmptable_readwrite_cost( | |
| 10810 | tmp_table_type, 0.0, distinct_rowcount); | ||
| 10811 | 2617 | sjm->scan_cost.add_io(scan_cost); | |
| 10812 | } | ||
| 10813 | |||
| 10814 | // The cost to lookup a row in temp. table | ||
| 10815 | const double row_cost = | ||
| 10816 | 2635 | cost_model->tmptable_readwrite_cost(tmp_table_type, 0.0, 1.0); | |
| 10817 | 2635 | sjm->lookup_cost.reset(); | |
| 10818 | 2635 | sjm->lookup_cost.add_io(row_cost); | |
| 10819 | 2635 | } | |
| 10820 | |||
| 10821 | /** | ||
| 10822 | Decides between EXISTS and materialization; performs last steps to set up | ||
| 10823 | the chosen strategy. | ||
| 10824 | @returns 'false' if no error | ||
| 10825 | |||
| 10826 | @note If UNION this is called on each contained JOIN. | ||
| 10827 | |||
| 10828 | */ | ||
| 10829 | 81723 | bool JOIN::decide_subquery_strategy() { | |
| 10830 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 81723 times.
|
81723 | assert(query_expression()->item); |
| 10831 | |||
| 10832 |
3/4✓ Branch 0 taken 81723 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1043 times.
✓ Branch 3 taken 80680 times.
|
81723 | switch (query_expression()->item->substype()) { |
| 10833 | 1043 | case Item_subselect::IN_SUBS: | |
| 10834 | case Item_subselect::ALL_SUBS: | ||
| 10835 | case Item_subselect::ANY_SUBS: | ||
| 10836 | // All of those are children of Item_in_subselect and may use EXISTS | ||
| 10837 | 1043 | break; | |
| 10838 | 80680 | default: | |
| 10839 | 80680 | return false; | |
| 10840 | } | ||
| 10841 | |||
| 10842 | Item_in_subselect *const in_pred = | ||
| 10843 | 1043 | static_cast<Item_in_subselect *>(query_expression()->item); | |
| 10844 | |||
| 10845 | 1043 | Subquery_strategy chosen_method = in_pred->strategy; | |
| 10846 | // Materialization does not allow UNION so this can't happen: | ||
| 10847 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1043 times.
|
1043 | assert(chosen_method != Subquery_strategy::SUBQ_MATERIALIZATION); |
| 10848 | |||
| 10849 |
3/4✓ Branch 0 taken 1025 times.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1043 times.
|
2068 | if ((chosen_method == Subquery_strategy::CANDIDATE_FOR_IN2EXISTS_OR_MAT) && |
| 10850 |
2/4✓ Branch 0 taken 1025 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1025 times.
|
1025 | compare_costs_of_subquery_strategies(&chosen_method)) |
| 10851 | ✗ | return true; | |
| 10852 | |||
| 10853 |
2/3✓ Branch 0 taken 893 times.
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
|
1043 | switch (chosen_method) { |
| 10854 | 893 | case Subquery_strategy::SUBQ_EXISTS: | |
| 10855 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 886 times.
|
893 | if (query_block->m_windows.elements > 0) // grep for WL#10431 |
| 10856 | { | ||
| 10857 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | my_error(ER_NOT_SUPPORTED_YET, MYF(0), |
| 10858 | "the combination of this ALL/ANY/SOME/IN subquery with this" | ||
| 10859 | " comparison operator and with contained window functions"); | ||
| 10860 | 7 | return true; | |
| 10861 | } | ||
| 10862 |
1/2✓ Branch 0 taken 886 times.
✗ Branch 1 not taken.
|
886 | return in_pred->finalize_exists_transform(thd, query_block); |
| 10863 | 150 | case Subquery_strategy::SUBQ_MATERIALIZATION: | |
| 10864 |
1/2✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
|
150 | return in_pred->finalize_materialization_transform(thd, this); |
| 10865 | ✗ | default: | |
| 10866 | ✗ | assert(false); | |
| 10867 | return true; | ||
| 10868 | } | ||
| 10869 | } | ||
| 10870 | |||
| 10871 | /** | ||
| 10872 | Tells what is the cheapest between IN->EXISTS and subquery materialization, | ||
| 10873 | in terms of cost, for the subquery's JOIN. | ||
| 10874 | Input: | ||
| 10875 | - join->{best_positions,best_read,best_rowcount} must contain the | ||
| 10876 | execution plan of EXISTS (where 'join' is the subquery's JOIN) | ||
| 10877 | - join2->{best_positions,best_read,best_rowcount} must be correctly set | ||
| 10878 | (where 'join2' is the parent join, the grandparent join, etc). | ||
| 10879 | Output: | ||
| 10880 | join->{best_positions,best_read,best_rowcount} contain the cheapest | ||
| 10881 | execution plan (where 'join' is the subquery's JOIN). | ||
| 10882 | |||
| 10883 | This plan choice has to happen before calling functions which set up | ||
| 10884 | execution structures, like JOIN::get_best_combination(). | ||
| 10885 | |||
| 10886 | @param[out] method chosen method (EXISTS or materialization) will be put | ||
| 10887 | here. | ||
| 10888 | @returns false if success | ||
| 10889 | */ | ||
| 10890 | 1025 | bool JOIN::compare_costs_of_subquery_strategies(Subquery_strategy *method) { | |
| 10891 | 1025 | *method = Subquery_strategy::SUBQ_EXISTS; | |
| 10892 | |||
| 10893 |
1/2✓ Branch 0 taken 1025 times.
✗ Branch 1 not taken.
|
1025 | Subquery_strategy allowed_strategies = query_block->subquery_strategy(thd); |
| 10894 | |||
| 10895 | /* | ||
| 10896 | A non-deterministic subquery should not use materialization, unless forced. | ||
| 10897 | For a detailed explanation, see Query_block::decorrelate_where_cond(). | ||
| 10898 | Here, the same logic is applied also for subqueries that are not converted | ||
| 10899 | to semi-join. | ||
| 10900 | */ | ||
| 10901 |
4/4✓ Branch 0 taken 752 times.
✓ Branch 1 taken 273 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1019 times.
|
1777 | if (allowed_strategies == Subquery_strategy::CANDIDATE_FOR_IN2EXISTS_OR_MAT && |
| 10902 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 746 times.
|
752 | (query_expression()->uncacheable & UNCACHEABLE_RAND)) |
| 10903 | 6 | allowed_strategies = Subquery_strategy::SUBQ_EXISTS; | |
| 10904 | |||
| 10905 |
2/2✓ Branch 0 taken 257 times.
✓ Branch 1 taken 768 times.
|
1025 | if (allowed_strategies == Subquery_strategy::SUBQ_EXISTS) return false; |
| 10906 | |||
| 10907 |
3/4✓ Branch 0 taken 22 times.
✓ Branch 1 taken 746 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
|
768 | assert(allowed_strategies == |
| 10908 | Subquery_strategy::CANDIDATE_FOR_IN2EXISTS_OR_MAT || | ||
| 10909 | allowed_strategies == Subquery_strategy::SUBQ_MATERIALIZATION); | ||
| 10910 | |||
| 10911 | 768 | const JOIN *parent_join = query_expression()->outer_query_block()->join; | |
| 10912 |
4/4✓ Branch 0 taken 733 times.
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 101 times.
✓ Branch 3 taken 632 times.
|
768 | if (!parent_join || !parent_join->child_subquery_can_materialize) |
| 10913 | 136 | return false; | |
| 10914 | |||
| 10915 | Item_in_subselect *const in_pred = | ||
| 10916 | 632 | static_cast<Item_in_subselect *>(query_expression()->item); | |
| 10917 | |||
| 10918 | /* | ||
| 10919 | Testing subquery_allows_etc() at each optimization is necessary as each | ||
| 10920 | execution of a prepared statement may use a different type of parameter. | ||
| 10921 | */ | ||
| 10922 |
2/2✓ Branch 0 taken 330 times.
✓ Branch 1 taken 302 times.
|
632 | if (!in_pred->subquery_allows_materialization( |
| 10923 |
1/2✓ Branch 0 taken 632 times.
✗ Branch 1 not taken.
|
632 | thd, query_block, query_block->outer_query_block())) |
| 10924 | 330 | return false; | |
| 10925 | |||
| 10926 | 302 | Opt_trace_context *const trace = &thd->opt_trace; | |
| 10927 |
1/2✓ Branch 0 taken 302 times.
✗ Branch 1 not taken.
|
302 | Opt_trace_object trace_wrapper(trace); |
| 10928 | Opt_trace_object trace_subqmat( | ||
| 10929 |
1/2✓ Branch 0 taken 302 times.
✗ Branch 1 not taken.
|
302 | trace, "execution_plan_for_potential_materialization"); |
| 10930 | 302 | const double saved_best_read = best_read; | |
| 10931 | 302 | const ha_rows saved_best_rowcount = best_rowcount; | |
| 10932 | 302 | POSITION *const saved_best_pos = best_positions; | |
| 10933 | |||
| 10934 |
2/2✓ Branch 0 taken 240 times.
✓ Branch 1 taken 62 times.
|
302 | if (in_pred->in2exists_added_to_where()) { |
| 10935 |
1/2✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
|
240 | Opt_trace_array trace_subqmat_steps(trace, "steps"); |
| 10936 | |||
| 10937 | // Up to one extra slot per semi-join nest is needed (if materialized) | ||
| 10938 | 240 | const uint sj_nests = query_block->sj_nests.size(); | |
| 10939 | |||
| 10940 |
2/4✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 240 times.
|
240 | if (!(best_positions = new (thd->mem_root) POSITION[tables + sj_nests])) |
| 10941 | ✗ | return true; | |
| 10942 | |||
| 10943 | // Compute plans which do not use outer references | ||
| 10944 | |||
| 10945 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
|
240 | assert(allow_outer_refs); |
| 10946 | 240 | allow_outer_refs = false; | |
| 10947 | |||
| 10948 |
2/4✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 240 times.
|
240 | if (optimize_semijoin_nests_for_materialization(this)) return true; |
| 10949 | |||
| 10950 |
3/6✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 240 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 240 times.
|
240 | if (Optimize_table_order(thd, this, nullptr).choose_table_order()) |
| 10951 | ✗ | return true; | |
| 10952 |
1/2✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
|
240 | } else { |
| 10953 | /* | ||
| 10954 | If IN->EXISTS didn't add any condition to WHERE (only to HAVING, which | ||
| 10955 | can happen if subquery has aggregates) then the plan for materialization | ||
| 10956 | will be the same as for EXISTS - don't compute it again. | ||
| 10957 | */ | ||
| 10958 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | trace_subqmat.add("surely_same_plan_as_EXISTS", true) |
| 10959 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | .add_alnum("cause", "EXISTS_did_not_change_WHERE"); |
| 10960 | } | ||
| 10961 | |||
| 10962 | 302 | Semijoin_mat_optimize sjm; | |
| 10963 |
1/2✓ Branch 0 taken 302 times.
✗ Branch 1 not taken.
|
302 | calculate_materialization_costs(this, nullptr, primary_tables, &sjm); |
| 10964 | |||
| 10965 | /* | ||
| 10966 | The number of evaluations of the subquery influences costs, we need to | ||
| 10967 | compute it. | ||
| 10968 | */ | ||
| 10969 |
1/2✓ Branch 0 taken 302 times.
✗ Branch 1 not taken.
|
302 | Opt_trace_object trace_subq_mat_decision(trace, "subq_mat_decision"); |
| 10970 |
1/2✓ Branch 0 taken 302 times.
✗ Branch 1 not taken.
|
302 | const double subq_executions = calculate_subquery_executions(in_pred, trace); |
| 10971 | 302 | const double cost_exists = subq_executions * saved_best_read; | |
| 10972 | 302 | const double cost_mat_table = sjm.materialization_cost.total_cost(); | |
| 10973 | const double cost_mat = | ||
| 10974 | 302 | cost_mat_table + subq_executions * sjm.lookup_cost.total_cost(); | |
| 10975 | 302 | const bool mat_chosen = | |
| 10976 | (allowed_strategies == Subquery_strategy::CANDIDATE_FOR_IN2EXISTS_OR_MAT) | ||
| 10977 |
4/4✓ Branch 0 taken 288 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 136 times.
✓ Branch 3 taken 152 times.
|
302 | ? (cost_mat < cost_exists) |
| 10978 | : true; | ||
| 10979 | trace_subq_mat_decision | ||
| 10980 |
1/2✓ Branch 0 taken 302 times.
✗ Branch 1 not taken.
|
302 | .add("cost_to_create_and_fill_materialized_table", cost_mat_table) |
| 10981 |
1/2✓ Branch 0 taken 302 times.
✗ Branch 1 not taken.
|
302 | .add("cost_of_one_EXISTS", saved_best_read) |
| 10982 |
1/2✓ Branch 0 taken 302 times.
✗ Branch 1 not taken.
|
302 | .add("number_of_subquery_evaluations", subq_executions) |
| 10983 |
1/2✓ Branch 0 taken 302 times.
✗ Branch 1 not taken.
|
302 | .add("cost_of_materialization", cost_mat) |
| 10984 |
1/2✓ Branch 0 taken 302 times.
✗ Branch 1 not taken.
|
302 | .add("cost_of_EXISTS", cost_exists) |
| 10985 |
1/2✓ Branch 0 taken 302 times.
✗ Branch 1 not taken.
|
302 | .add("chosen", mat_chosen); |
| 10986 |
2/2✓ Branch 0 taken 150 times.
✓ Branch 1 taken 152 times.
|
302 | if (mat_chosen) { |
| 10987 | 150 | *method = Subquery_strategy::SUBQ_MATERIALIZATION; | |
| 10988 | } else { | ||
| 10989 | 152 | best_read = saved_best_read; | |
| 10990 | 152 | best_rowcount = saved_best_rowcount; | |
| 10991 | 152 | best_positions = saved_best_pos; | |
| 10992 | /* | ||
| 10993 | Don't restore JOIN::positions or best_ref, they're not used | ||
| 10994 | afterwards. best_positions is (like: by get_sj_strategy()). | ||
| 10995 | */ | ||
| 10996 | } | ||
| 10997 | 302 | return false; | |
| 10998 | 302 | } | |
| 10999 | |||
| 11000 | 2760 | double calculate_subquery_executions(const Item_subselect *subquery, | |
| 11001 | Opt_trace_context *trace) { | ||
| 11002 |
1/2✓ Branch 0 taken 2760 times.
✗ Branch 1 not taken.
|
2760 | Opt_trace_array trace_parents(trace, "parent_fanouts"); |
| 11003 | 2760 | double subquery_executions = 1.0; | |
| 11004 | for (;;) { | ||
| 11005 | const Query_block *const parent_query_block = | ||
| 11006 | 6492 | subquery->unit->outer_query_block(); | |
| 11007 | 6492 | const JOIN *const parent_join = parent_query_block->join; | |
| 11008 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6492 times.
|
6492 | if (parent_join == nullptr) { |
| 11009 | /* | ||
| 11010 | May be single-table UPDATE/DELETE, has no join. | ||
| 11011 | @todo we should find how many rows it plans to UPDATE/DELETE, taking | ||
| 11012 | inspiration in Explain_table::explain_rows_and_filtered(). | ||
| 11013 | This is not a priority as it applies only to | ||
| 11014 | UPDATE - child(non-mat-subq) - grandchild(may-be-mat-subq). | ||
| 11015 | And it will autosolve the day UPDATE gets a JOIN. | ||
| 11016 | */ | ||
| 11017 | ✗ | break; | |
| 11018 | } | ||
| 11019 | |||
| 11020 |
1/2✓ Branch 0 taken 6492 times.
✗ Branch 1 not taken.
|
6492 | Opt_trace_object trace_parent(trace); |
| 11021 |
1/2✓ Branch 0 taken 6492 times.
✗ Branch 1 not taken.
|
6492 | trace_parent.add_select_number(parent_query_block->select_number); |
| 11022 | double parent_fanout; | ||
| 11023 | 6492 | if ( // safety, not sure needed | |
| 11024 |
4/4✓ Branch 0 taken 2423 times.
✓ Branch 1 taken 4069 times.
✓ Branch 2 taken 4069 times.
✓ Branch 3 taken 2423 times.
|
8915 | parent_join->plan_is_const() || |
| 11025 | // if subq is in condition on constant table: | ||
| 11026 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2423 times.
|
2423 | !parent_join->child_subquery_can_materialize) { |
| 11027 | 4069 | parent_fanout = 1.0; | |
| 11028 |
1/2✓ Branch 0 taken 4069 times.
✗ Branch 1 not taken.
|
4069 | trace_parent.add("subq_attached_to_const_table", true); |
| 11029 | } else { | ||
| 11030 |
2/2✓ Branch 0 taken 1443 times.
✓ Branch 1 taken 980 times.
|
2423 | if (subquery->in_cond_of_tab != NO_PLAN_IDX) { |
| 11031 | /* | ||
| 11032 | Subquery is attached to a certain 'pos', pos[-1].prefix_rowcount | ||
| 11033 | is the number of times we'll start a loop accessing 'pos'; each such | ||
| 11034 | loop will read pos->rows_fetched rows of 'pos', so subquery will | ||
| 11035 | be evaluated pos[-1].prefix_rowcount * pos->rows_fetched times. | ||
| 11036 | Exceptions: | ||
| 11037 | - if 'pos' is first, use 1.0 instead of pos[-1].prefix_rowcount | ||
| 11038 | - if 'pos' is first of a sj-materialization nest, same. | ||
| 11039 | |||
| 11040 | If in a sj-materialization nest, pos->rows_fetched and | ||
| 11041 | pos[-1].prefix_rowcount are of the "nest materialization" plan | ||
| 11042 | (copied back in fix_semijoin_strategies()), which is | ||
| 11043 | appropriate as it corresponds to evaluations of our subquery. | ||
| 11044 | |||
| 11045 | pos->prefix_rowcount is not suitable because if we have: | ||
| 11046 | select ... from ot1 where ot1.col in | ||
| 11047 | (select it1.col1 from it1 where it1.col2 not in (subq)); | ||
| 11048 | and subq does subq-mat, and plan is ot1 - it1+firstmatch(ot1), | ||
| 11049 | then: | ||
| 11050 | - t1.prefix_rowcount==1 (due to firstmatch) | ||
| 11051 | - subq is attached to it1, and is evaluated for each row read from | ||
| 11052 | t1, potentially way more than 1. | ||
| 11053 | */ | ||
| 11054 | 1443 | const uint idx = subquery->in_cond_of_tab; | |
| 11055 |
2/4✓ Branch 0 taken 1443 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1443 times.
✗ Branch 3 not taken.
|
1443 | assert((int)idx >= 0 && idx < parent_join->tables); |
| 11056 |
1/2✓ Branch 0 taken 1443 times.
✗ Branch 1 not taken.
|
1443 | trace_parent.add("subq_attached_to_table", true); |
| 11057 | 1443 | QEP_TAB *const parent_tab = &parent_join->qep_tab[idx]; | |
| 11058 |
1/2✓ Branch 0 taken 1443 times.
✗ Branch 1 not taken.
|
1443 | trace_parent.add_utf8_table(parent_tab->table_ref); |
| 11059 | 1443 | parent_fanout = parent_tab->position()->rows_fetched; | |
| 11060 |
4/4✓ Branch 0 taken 144 times.
✓ Branch 1 taken 1299 times.
✓ Branch 2 taken 140 times.
✓ Branch 3 taken 1303 times.
|
1587 | if ((idx > parent_join->const_tables) && |
| 11061 |
2/2✓ Branch 0 taken 140 times.
✓ Branch 1 taken 4 times.
|
144 | !sj_is_materialize_strategy(parent_tab->position()->sj_strategy)) |
| 11062 | 140 | parent_fanout *= parent_tab[-1].position()->prefix_rowcount; | |
| 11063 | } else { | ||
| 11064 | /* | ||
| 11065 | Subquery is SELECT list, GROUP BY, ORDER BY, HAVING: it is evaluated | ||
| 11066 | at the end of the parent join's execution. | ||
| 11067 | It can be evaluated once per row-before-grouping: | ||
| 11068 | SELECT SUM(t1.col IN (subq)) FROM t1 GROUP BY expr; | ||
| 11069 | or once per row-after-grouping: | ||
| 11070 | SELECT SUM(t1.col) AS s FROM t1 GROUP BY expr HAVING s IN (subq), | ||
| 11071 | SELECT SUM(t1.col) IN (subq) FROM t1 GROUP BY expr | ||
| 11072 | It's hard to tell. We simply assume 'once per | ||
| 11073 | row-before-grouping'. | ||
| 11074 | |||
| 11075 | Another approximation: | ||
| 11076 | SELECT ... HAVING x IN (subq) LIMIT 1 | ||
| 11077 | best_rowcount=1 due to LIMIT, though HAVING (and thus the subquery) | ||
| 11078 | may be evaluated many times before HAVING becomes true and the limit | ||
| 11079 | is reached. | ||
| 11080 | */ | ||
| 11081 |
1/2✓ Branch 0 taken 980 times.
✗ Branch 1 not taken.
|
980 | trace_parent.add("subq_attached_to_join_result", true); |
| 11082 | 980 | parent_fanout = static_cast<double>(parent_join->best_rowcount); | |
| 11083 | } | ||
| 11084 | } | ||
| 11085 | 6492 | subquery_executions *= parent_fanout; | |
| 11086 |
1/2✓ Branch 0 taken 6492 times.
✗ Branch 1 not taken.
|
6492 | trace_parent.add("fanout", parent_fanout); |
| 11087 | 6492 | const bool cacheable = parent_query_block->is_cacheable(); | |
| 11088 |
1/2✓ Branch 0 taken 6492 times.
✗ Branch 1 not taken.
|
6492 | trace_parent.add("cacheable", cacheable); |
| 11089 |
2/2✓ Branch 0 taken 2482 times.
✓ Branch 1 taken 4010 times.
|
6492 | if (cacheable) { |
| 11090 | // Parent executed only once | ||
| 11091 | 2482 | break; | |
| 11092 | } | ||
| 11093 | /* | ||
| 11094 | Parent query is executed once per outer row => go up to find number of | ||
| 11095 | outer rows. Example: | ||
| 11096 | SELECT ... IN(subq-with-in2exists WHERE ... IN (subq-with-mat)) | ||
| 11097 | */ | ||
| 11098 | 4010 | subquery = parent_join->query_expression()->item; | |
| 11099 |
2/2✓ Branch 0 taken 278 times.
✓ Branch 1 taken 3732 times.
|
4010 | if (subquery == nullptr) { |
| 11100 | // derived table, materialized only once | ||
| 11101 | 278 | break; | |
| 11102 | } | ||
| 11103 |
2/2✓ Branch 0 taken 3732 times.
✓ Branch 1 taken 2760 times.
|
10224 | } // for(;;) |
| 11104 | 2760 | return subquery_executions; | |
| 11105 | 2760 | } | |
| 11106 | |||
| 11107 | /** | ||
| 11108 | Optimize rollup specification. | ||
| 11109 | |||
| 11110 | Allocate objects needed for rollup processing. | ||
| 11111 | |||
| 11112 | @returns false if success, true if error. | ||
| 11113 | */ | ||
| 11114 | |||
| 11115 | 334 | bool JOIN::optimize_rollup() { | |
| 11116 | 334 | tmp_table_param.allow_group_via_temp_table = false; | |
| 11117 | 334 | rollup_state = RollupState::INITED; | |
| 11118 | 334 | tmp_table_param.group_parts = send_group_parts; | |
| 11119 | 334 | return false; | |
| 11120 | } | ||
| 11121 | |||
| 11122 | /** | ||
| 11123 | Refine the best_rowcount estimation based on what happens after tables | ||
| 11124 | have been joined: LIMIT and type of result sink. | ||
| 11125 | */ | ||
| 11126 | 1911993 | void JOIN::refine_best_rowcount() { | |
| 11127 | // If plan is const, 0 or 1 rows should be returned | ||
| 11128 |
3/4✓ Branch 0 taken 96356 times.
✓ Branch 1 taken 1815646 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 96356 times.
|
1911993 | assert(!plan_is_const() || best_rowcount <= 1); |
| 11129 | |||
| 11130 |
2/2✓ Branch 0 taken 96356 times.
✓ Branch 1 taken 1815648 times.
|
1912002 | if (plan_is_const()) return; |
| 11131 | |||
| 11132 | /* | ||
| 11133 | If a derived table, or a member of a UNION which itself forms a derived | ||
| 11134 | table: | ||
| 11135 | setting estimate to 0 or 1 row would mark the derived table as const. | ||
| 11136 | The row count is bumped to the nearest higher value, so that the | ||
| 11137 | query block will not be evaluated during optimization. | ||
| 11138 | */ | ||
| 11139 |
4/4✓ Branch 0 taken 478662 times.
✓ Branch 1 taken 1336986 times.
✓ Branch 2 taken 3263 times.
✓ Branch 3 taken 1812379 times.
|
2294304 | if (best_rowcount <= 1 && |
| 11140 |
2/2✓ Branch 0 taken 3263 times.
✓ Branch 1 taken 475393 times.
|
478662 | query_block->master_query_expression()->first_query_block()->linkage == |
| 11141 | DERIVED_TABLE_TYPE) | ||
| 11142 | 3263 | best_rowcount = PLACEHOLDER_TABLE_ROW_ESTIMATE; | |
| 11143 | |||
| 11144 | /* | ||
| 11145 | There will be no more rows than defined in the LIMIT clause. Use it | ||
| 11146 | as an estimate. If LIMIT 1 is specified, the query block will be | ||
| 11147 | considered "const", with actual row count 0 or 1. | ||
| 11148 | */ | ||
| 11149 | 1815642 | best_rowcount = std::min(best_rowcount, query_expression()->select_limit_cnt); | |
| 11150 | } | ||
| 11151 | |||
| 11152 | 114424 | mem_root_deque<Item *> *JOIN::get_current_fields() { | |
| 11153 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 114424 times.
|
114424 | assert((int)current_ref_item_slice >= 0); |
| 11154 |
2/2✓ Branch 0 taken 114421 times.
✓ Branch 1 taken 3 times.
|
114424 | if (current_ref_item_slice == REF_SLICE_SAVED_BASE) return fields; |
| 11155 | 3 | return &tmp_fields[current_ref_item_slice]; | |
| 11156 | } | ||
| 11157 | |||
| 11158 | 595347372 | const Cost_model_server *JOIN::cost_model() const { | |
| 11159 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 595347372 times.
|
595347372 | assert(thd != nullptr); |
| 11160 | 595347372 | return thd->cost_model(); | |
| 11161 | } | ||
| 11162 | |||
| 11163 | /** | ||
| 11164 | @} (end of group Query_Optimizer) | ||
| 11165 | */ | ||
| 11166 | |||
| 11167 | /** | ||
| 11168 | This function is used to get the key length of Item object on | ||
| 11169 | which one tmp field will be created during create_tmp_table. | ||
| 11170 | This function references KEY_PART_INFO::init_from_field(). | ||
| 11171 | |||
| 11172 | @param item A inner item of outer join | ||
| 11173 | |||
| 11174 | @return The length of a item to be as a key of a temp table | ||
| 11175 | */ | ||
| 11176 | |||
| 11177 | 2392 | static uint32 get_key_length_tmp_table(Item *item) { | |
| 11178 | 2392 | uint32 len = 0; | |
| 11179 | |||
| 11180 | 2392 | item = item->real_item(); | |
| 11181 |
2/2✓ Branch 0 taken 1221 times.
✓ Branch 1 taken 1171 times.
|
2392 | if (item->type() == Item::FIELD_ITEM) |
| 11182 | 1221 | len = ((Item_field *)item)->field->key_length(); | |
| 11183 | else | ||
| 11184 | 1171 | len = item->max_length; | |
| 11185 | |||
| 11186 |
2/2✓ Branch 0 taken 1973 times.
✓ Branch 1 taken 419 times.
|
2392 | if (item->is_nullable()) len += HA_KEY_NULL_LENGTH; |
| 11187 | |||
| 11188 | // references KEY_PART_INFO::init_from_field() | ||
| 11189 | 2392 | enum_field_types type = item->data_type(); | |
| 11190 |
5/6✓ Branch 0 taken 2391 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1435 times.
✓ Branch 3 taken 956 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1435 times.
|
2392 | if (type == MYSQL_TYPE_BLOB || type == MYSQL_TYPE_VARCHAR || |
| 11191 | type == MYSQL_TYPE_GEOMETRY) | ||
| 11192 | 957 | len += HA_KEY_BLOB_LENGTH; | |
| 11193 | |||
| 11194 | 2392 | return len; | |
| 11195 | } | ||
| 11196 | |||
| 11197 | 5915127 | bool evaluate_during_optimization(const Item *item, const Query_block *select) { | |
| 11198 | /* | ||
| 11199 | Should only be called on items that are const_for_execution(), as those | ||
| 11200 | items are the only ones that are allowed to be evaluated during optimization | ||
| 11201 | in the first place. | ||
| 11202 | |||
| 11203 | Additionally, allow items that only access tables in JOIN::const_table_map. | ||
| 11204 | This should not be necessary, but the const_for_execution() property is not | ||
| 11205 | always updated correctly by update_used_tables() for certain subqueries. | ||
| 11206 | */ | ||
| 11207 |
3/4✓ Branch 0 taken 71 times.
✓ Branch 1 taken 5915133 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 71 times.
|
5915127 | assert(item->const_for_execution() || |
| 11208 | (item->used_tables() & ~select->join->const_table_map) == 0); | ||
| 11209 | |||
| 11210 | // If the Item does not access any tables, it can always be evaluated. | ||
| 11211 |
2/2✓ Branch 0 taken 5344420 times.
✓ Branch 1 taken 570813 times.
|
5915204 | if (item->const_item()) return true; |
| 11212 | |||
| 11213 |
4/4✓ Branch 0 taken 4803 times.
✓ Branch 1 taken 566035 times.
✓ Branch 2 taken 4798 times.
✓ Branch 3 taken 6 times.
|
570813 | return !item->has_subquery() || (select->active_options() & |
| 11214 | 570839 | OPTION_NO_SUBQUERY_DURING_OPTIMIZATION) == 0; | |
| 11215 | } | ||
| 11216 |